Commit | Line | Data |
---|---|---|
0c230560 | 1 | /*- |
41a4fbbe MT |
2 | * Copyright (c) 1989 The Regents of the University of California. |
3 | * All rights reserved. | |
4 | * | |
0c230560 | 5 | * %sccs.include.redist.c% |
41a4fbbe MT |
6 | */ |
7 | ||
0c230560 | 8 | #if defined(LIBC_SCCS) && !defined(lint) |
1b1d1f0f | 9 | static char sccsid[] = "@(#)kvm.c 5.21 (Berkeley) %G%"; |
0c230560 | 10 | #endif /* LIBC_SCCS and not lint */ |
41a4fbbe | 11 | |
41a4fbbe | 12 | #include <sys/param.h> |
469444a6 | 13 | #include <sys/user.h> |
41a4fbbe | 14 | #include <sys/proc.h> |
41a4fbbe | 15 | #include <sys/ioctl.h> |
c45ee70b | 16 | #include <sys/kinfo.h> |
41a4fbbe | 17 | #include <sys/tty.h> |
837ee677 | 18 | #include <machine/vmparam.h> |
c45ee70b | 19 | #include <fcntl.h> |
41a4fbbe | 20 | #include <nlist.h> |
469444a6 | 21 | #include <kvm.h> |
41a4fbbe MT |
22 | #include <ndbm.h> |
23 | #include <limits.h> | |
24 | #include <paths.h> | |
0e005c87 | 25 | #include <stdio.h> |
c45ee70b | 26 | #include <string.h> |
41a4fbbe | 27 | |
837ee677 MK |
28 | #ifdef SPPWAIT |
29 | #define NEWVM | |
30 | #endif | |
31 | ||
32 | #ifdef NEWVM | |
33 | #define btop(x) (((unsigned)(x)) >> PGSHIFT) /* XXX */ | |
34 | #define ptob(x) ((caddr_t)((x) << PGSHIFT)) /* XXX */ | |
35 | #include <vm/vm.h> /* ??? kinfo_proc currently includes this*/ | |
36 | #include <sys/kinfo_proc.h> | |
469444a6 MK |
37 | #ifdef hp300 |
38 | #include <hp300/hp300/pte.h> | |
39 | #endif | |
40 | #else /* NEWVM */ | |
837ee677 MK |
41 | #include <machine/pte.h> |
42 | #include <sys/vmmac.h> | |
43 | #include <sys/text.h> | |
469444a6 | 44 | #endif /* NEWVM */ |
837ee677 | 45 | |
41a4fbbe MT |
46 | /* |
47 | * files | |
48 | */ | |
469444a6 | 49 | static const char *unixf, *memf, *kmemf, *swapf; |
41a4fbbe | 50 | static int unixx, mem, kmem, swap; |
0e005c87 | 51 | static DBM *db; |
41a4fbbe MT |
52 | /* |
53 | * flags | |
54 | */ | |
55 | static int deadkernel; | |
56 | static int kvminit = 0; | |
57 | static int kvmfilesopen = 0; | |
58 | /* | |
59 | * state | |
60 | */ | |
61 | static struct kinfo_proc *kvmprocbase, *kvmprocptr; | |
62 | static int kvmnprocs; | |
41a4fbbe MT |
63 | /* |
64 | * u. buffer | |
65 | */ | |
66 | static union { | |
67 | struct user user; | |
68 | char upages[UPAGES][NBPG]; | |
69 | } user; | |
70 | /* | |
71 | * random other stuff | |
72 | */ | |
469444a6 | 73 | #ifndef NEWVM |
41a4fbbe | 74 | static struct pte *Usrptmap, *usrpt; |
41a4fbbe MT |
75 | static struct pte *Sysmap; |
76 | static int Syssize; | |
469444a6 MK |
77 | #endif |
78 | static int dmmin, dmmax; | |
bd6478f9 KB |
79 | static int pcbpf; |
80 | static int argaddr0; /* XXX */ | |
81 | static int argaddr1; | |
41a4fbbe | 82 | static int nswap; |
0e005c87 | 83 | static char *tmp; |
bd6478f9 KB |
84 | #if defined(hp300) |
85 | static int lowram; | |
837ee677 | 86 | static struct ste *Sysseg; |
bd6478f9 | 87 | #endif |
41a4fbbe | 88 | |
0e005c87 | 89 | #define basename(cp) ((tmp=rindex((cp), '/')) ? tmp+1 : (cp)) |
41a4fbbe | 90 | #define MAXSYMSIZE 256 |
41a4fbbe | 91 | |
bd6478f9 KB |
92 | #if defined(hp300) |
93 | #define pftoc(f) ((f) - lowram) | |
94 | #define iskva(v) (1) | |
95 | #endif | |
96 | ||
97 | #ifndef pftoc | |
98 | #define pftoc(f) (f) | |
99 | #endif | |
100 | #ifndef iskva | |
d0e536aa | 101 | #define iskva(v) ((u_long)(v) & KERNBASE) |
bd6478f9 KB |
102 | #endif |
103 | ||
41a4fbbe | 104 | static struct nlist nl[] = { |
41a4fbbe | 105 | { "_nswap" }, |
3c4639f9 | 106 | #define X_NSWAP 0 |
41a4fbbe | 107 | { "_dmmin" }, |
3c4639f9 | 108 | #define X_DMMIN X_NSWAP+1 |
41a4fbbe | 109 | { "_dmmax" }, |
3c4639f9 | 110 | #define X_DMMAX X_DMMIN+1 |
41a4fbbe MT |
111 | /* |
112 | * everything here and down, only if a dead kernel | |
113 | */ | |
114 | { "_Sysmap" }, | |
3c4639f9 | 115 | #define X_SYSMAP X_DMMAX+1 |
bd6478f9 | 116 | #define X_DEADKERNEL X_SYSMAP |
41a4fbbe | 117 | { "_allproc" }, |
3c4639f9 | 118 | #define X_ALLPROC X_SYSMAP+1 |
41a4fbbe | 119 | { "_zombproc" }, |
3c4639f9 MT |
120 | #define X_ZOMBPROC X_ALLPROC+1 |
121 | { "_nprocs" }, | |
122 | #define X_NPROCS X_ZOMBPROC+1 | |
bd6478f9 | 123 | #if defined(hp300) |
837ee677 | 124 | { "_Sysseg" }, |
3c4639f9 | 125 | #define X_SYSSEG (X_NPROCS+1) |
bd6478f9 | 126 | { "_lowram" }, |
3c4639f9 | 127 | #define X_LOWRAM (X_SYSSEG+1) |
bd6478f9 | 128 | #endif |
41a4fbbe MT |
129 | { "" }, |
130 | }; | |
131 | ||
cc66874e | 132 | static off_t vtophys(); |
eeceacd9 MT |
133 | static void seterr(), setsyserr(), vstodb(); |
134 | static int getkvars(), kvm_doprocs(), kvm_init(), klseek(); | |
cc66874e | 135 | |
0e005c87 MT |
136 | /* |
137 | * returns 0 if files were opened now, | |
138 | * 1 if files were already opened, | |
139 | * -1 if files could not be opened. | |
140 | */ | |
41a4fbbe | 141 | kvm_openfiles(uf, mf, sf) |
469444a6 | 142 | const char *uf, *mf, *sf; |
0e005c87 MT |
143 | { |
144 | if (kvmfilesopen) | |
145 | return (1); | |
41a4fbbe MT |
146 | unixx = mem = kmem = swap = -1; |
147 | unixf = (uf == NULL) ? _PATH_UNIX : uf; | |
148 | memf = (mf == NULL) ? _PATH_MEM : mf; | |
149 | ||
150 | if ((unixx = open(unixf, O_RDONLY, 0)) == -1) { | |
151 | setsyserr("can't open %s", unixf); | |
152 | goto failed; | |
153 | } | |
154 | if ((mem = open(memf, O_RDONLY, 0)) == -1) { | |
155 | setsyserr("can't open %s", memf); | |
156 | goto failed; | |
157 | } | |
158 | if (sf != NULL) | |
159 | swapf = sf; | |
160 | if (mf != NULL) { | |
161 | deadkernel++; | |
162 | kmemf = mf; | |
163 | kmem = mem; | |
164 | swap = -1; | |
165 | } else { | |
166 | kmemf = _PATH_KMEM; | |
167 | if ((kmem = open(kmemf, O_RDONLY, 0)) == -1) { | |
168 | setsyserr("can't open %s", kmemf); | |
169 | goto failed; | |
170 | } | |
171 | swapf = (sf == NULL) ? _PATH_DRUM : sf; | |
172 | /* | |
173 | * live kernel - avoid looking up nlist entries | |
174 | * past X_DEADKERNEL. | |
175 | */ | |
176 | nl[X_DEADKERNEL].n_name = ""; | |
177 | } | |
178 | if (swapf != NULL && ((swap = open(swapf, O_RDONLY, 0)) == -1)) { | |
179 | seterr("can't open %s", swapf); | |
180 | goto failed; | |
181 | } | |
182 | kvmfilesopen++; | |
e245c64b MT |
183 | if (kvminit == 0 && kvm_init(NULL, NULL, NULL, 0) == -1) /*XXX*/ |
184 | return (-1); | |
41a4fbbe MT |
185 | return (0); |
186 | failed: | |
187 | kvm_close(); | |
188 | return (-1); | |
189 | } | |
190 | ||
0e005c87 MT |
191 | static |
192 | kvm_init(uf, mf, sf) | |
193 | char *uf, *mf, *sf; | |
194 | { | |
195 | if (kvmfilesopen == 0 && kvm_openfiles(NULL, NULL, NULL) == -1) | |
196 | return (-1); | |
197 | if (getkvars() == -1) | |
198 | return (-1); | |
199 | kvminit = 1; | |
200 | ||
201 | return (0); | |
202 | } | |
203 | ||
41a4fbbe MT |
204 | kvm_close() |
205 | { | |
0e005c87 | 206 | if (unixx != -1) { |
41a4fbbe | 207 | close(unixx); |
0e005c87 MT |
208 | unixx = -1; |
209 | } | |
210 | if (kmem != -1) { | |
211 | if (kmem != mem) | |
212 | close(kmem); | |
213 | /* otherwise kmem is a copy of mem, and will be closed below */ | |
214 | kmem = -1; | |
215 | } | |
216 | if (mem != -1) { | |
41a4fbbe | 217 | close(mem); |
0e005c87 MT |
218 | mem = -1; |
219 | } | |
220 | if (swap != -1) { | |
41a4fbbe | 221 | close(swap); |
0e005c87 MT |
222 | swap = -1; |
223 | } | |
224 | if (db != NULL) { | |
41a4fbbe | 225 | dbm_close(db); |
0e005c87 MT |
226 | db = NULL; |
227 | } | |
41a4fbbe MT |
228 | kvminit = 0; |
229 | kvmfilesopen = 0; | |
0e005c87 | 230 | deadkernel = 0; |
469444a6 | 231 | #ifndef NEWVM |
0e005c87 MT |
232 | if (Sysmap) { |
233 | free(Sysmap); | |
234 | Sysmap = NULL; | |
235 | } | |
469444a6 | 236 | #endif |
41a4fbbe MT |
237 | } |
238 | ||
239 | kvm_nlist(nl) | |
240 | struct nlist *nl; | |
241 | { | |
242 | datum key, data; | |
243 | char dbname[MAXPATHLEN]; | |
47587ec1 KB |
244 | char dbversion[_POSIX2_LINE_MAX]; |
245 | char kversion[_POSIX2_LINE_MAX]; | |
41a4fbbe | 246 | int dbversionlen; |
c45ee70b | 247 | char symbuf[MAXSYMSIZE]; |
41a4fbbe MT |
248 | struct nlist nbuf, *n; |
249 | int num, did; | |
250 | ||
251 | if (kvmfilesopen == 0 && kvm_openfiles(NULL, NULL, NULL) == -1) | |
252 | return (-1); | |
253 | if (deadkernel) | |
254 | goto hard2; | |
41a4fbbe | 255 | /* |
0e005c87 | 256 | * initialize key datum |
41a4fbbe MT |
257 | */ |
258 | key.dptr = symbuf; | |
0e005c87 MT |
259 | |
260 | if (db != NULL) | |
261 | goto win; /* off to the races */ | |
41a4fbbe | 262 | /* |
0e005c87 MT |
263 | * open database |
264 | */ | |
b36e1b5a | 265 | sprintf(dbname, "%s/kvm_%s", _PATH_VARRUN, basename(unixf)); |
0e005c87 MT |
266 | if ((db = dbm_open(dbname, O_RDONLY, 0)) == NULL) |
267 | goto hard2; | |
268 | /* | |
269 | * read version out of database | |
41a4fbbe | 270 | */ |
c45ee70b | 271 | bcopy("VERSION", symbuf, sizeof ("VERSION")-1); |
41a4fbbe MT |
272 | key.dsize = (sizeof ("VERSION") - 1) + 1; |
273 | data = dbm_fetch(db, key); | |
274 | if (data.dptr == NULL) | |
275 | goto hard1; | |
276 | bcopy(data.dptr, dbversion, data.dsize); | |
277 | dbversionlen = data.dsize; | |
278 | /* | |
279 | * read version string from kernel memory | |
280 | */ | |
c45ee70b | 281 | bcopy("_version", symbuf, sizeof ("_version")-1); |
41a4fbbe MT |
282 | key.dsize = (sizeof ("_version")-1) + 1; |
283 | data = dbm_fetch(db, key); | |
284 | if (data.dptr == NULL) | |
285 | goto hard1; | |
286 | if (data.dsize != sizeof (struct nlist)) | |
287 | goto hard1; | |
288 | bcopy(data.dptr, &nbuf, sizeof (struct nlist)); | |
289 | lseek(kmem, nbuf.n_value, 0); | |
290 | if (read(kmem, kversion, dbversionlen) != dbversionlen) | |
291 | goto hard1; | |
292 | /* | |
293 | * if they match, we win - otherwise do it the hard way | |
294 | */ | |
295 | if (bcmp(dbversion, kversion, dbversionlen) != 0) | |
296 | goto hard1; | |
297 | /* | |
298 | * getem from the database. | |
299 | */ | |
300 | win: | |
301 | num = did = 0; | |
302 | for (n = nl; n->n_name && n->n_name[0]; n++, num++) { | |
303 | int len; | |
304 | /* | |
0e005c87 | 305 | * clear out fields from users buffer |
41a4fbbe MT |
306 | */ |
307 | n->n_type = 0; | |
308 | n->n_other = 0; | |
309 | n->n_desc = 0; | |
310 | n->n_value = 0; | |
311 | /* | |
312 | * query db | |
313 | */ | |
314 | if ((len = strlen(n->n_name)) > MAXSYMSIZE) { | |
469444a6 | 315 | seterr("symbol too large"); |
41a4fbbe MT |
316 | return (-1); |
317 | } | |
c45ee70b | 318 | (void)strcpy(symbuf, n->n_name); |
41a4fbbe MT |
319 | key.dsize = len + 1; |
320 | data = dbm_fetch(db, key); | |
321 | if (data.dptr == NULL || data.dsize != sizeof (struct nlist)) | |
322 | continue; | |
323 | bcopy(data.dptr, &nbuf, sizeof (struct nlist)); | |
324 | n->n_value = nbuf.n_value; | |
325 | n->n_type = nbuf.n_type; | |
326 | n->n_desc = nbuf.n_desc; | |
327 | n->n_other = nbuf.n_other; | |
328 | did++; | |
329 | } | |
330 | return (num - did); | |
331 | hard1: | |
332 | dbm_close(db); | |
333 | db = NULL; | |
334 | hard2: | |
469444a6 MK |
335 | num = nlist(unixf, nl); |
336 | if (num == -1) | |
337 | seterr("nlist (hard way) failed"); | |
338 | return (num); | |
41a4fbbe MT |
339 | } |
340 | ||
341 | kvm_getprocs(what, arg) | |
cc66874e | 342 | int what, arg; |
41a4fbbe | 343 | { |
0e005c87 MT |
344 | if (kvminit == 0 && kvm_init(NULL, NULL, NULL, 0) == -1) |
345 | return (NULL); | |
41a4fbbe MT |
346 | if (!deadkernel) { |
347 | int ret, copysize; | |
348 | ||
349 | if ((ret = getkerninfo(what, NULL, NULL, arg)) == -1) { | |
350 | setsyserr("can't get estimate for kerninfo"); | |
351 | return (-1); | |
352 | } | |
353 | copysize = ret; | |
354 | if ((kvmprocbase = (struct kinfo_proc *)malloc(copysize)) | |
355 | == NULL) { | |
356 | seterr("out of memory"); | |
357 | return (-1); | |
358 | } | |
359 | if ((ret = getkerninfo(what, kvmprocbase, ©size, | |
360 | arg)) == -1) { | |
361 | setsyserr("can't get proc list"); | |
362 | return (-1); | |
363 | } | |
364 | if (copysize % sizeof (struct kinfo_proc)) { | |
837ee677 MK |
365 | seterr("proc size mismatch (got %d total, kinfo_proc: %d)", |
366 | copysize, sizeof (struct kinfo_proc)); | |
41a4fbbe MT |
367 | return (-1); |
368 | } | |
369 | kvmnprocs = copysize / sizeof (struct kinfo_proc); | |
370 | } else { | |
3c4639f9 | 371 | int nprocs; |
41a4fbbe | 372 | |
3c4639f9 | 373 | if (kvm_read((void *)nl[X_NPROCS].n_value, &nprocs, |
469444a6 | 374 | sizeof (int)) != sizeof (int)) { |
41a4fbbe MT |
375 | seterr("can't read nproc"); |
376 | return (-1); | |
377 | } | |
378 | if ((kvmprocbase = (struct kinfo_proc *) | |
3c4639f9 MT |
379 | malloc(nprocs * sizeof (struct kinfo_proc))) == NULL) { |
380 | seterr("out of memory (addr: %x nprocs = %d)", | |
381 | nl[X_NPROCS].n_value, nprocs); | |
41a4fbbe MT |
382 | return (-1); |
383 | } | |
384 | kvmnprocs = kvm_doprocs(what, arg, kvmprocbase); | |
385 | realloc(kvmprocbase, kvmnprocs * sizeof (struct kinfo_proc)); | |
386 | } | |
387 | kvmprocptr = kvmprocbase; | |
388 | ||
389 | return (kvmnprocs); | |
390 | } | |
391 | ||
392 | /* | |
393 | * XXX - should NOT give up so easily - especially since the kernel | |
394 | * may be corrupt (it died). Should gather as much information as possible. | |
395 | * Follows proc ptrs instead of reading table since table may go | |
396 | * away soon. | |
397 | */ | |
398 | static | |
399 | kvm_doprocs(what, arg, buff) | |
400 | int what, arg; | |
401 | char *buff; | |
402 | { | |
403 | struct proc *p, proc; | |
404 | register char *bp = buff; | |
405 | int i = 0; | |
406 | int doingzomb = 0; | |
407 | struct eproc eproc; | |
408 | struct pgrp pgrp; | |
409 | struct session sess; | |
410 | struct tty tty; | |
837ee677 | 411 | #ifndef NEWVM |
41a4fbbe | 412 | struct text text; |
837ee677 | 413 | #endif |
41a4fbbe MT |
414 | |
415 | /* allproc */ | |
469444a6 | 416 | if (kvm_read((void *) nl[X_ALLPROC].n_value, &p, |
41a4fbbe MT |
417 | sizeof (struct proc *)) != sizeof (struct proc *)) { |
418 | seterr("can't read allproc"); | |
419 | return (-1); | |
420 | } | |
421 | ||
422 | again: | |
423 | for (; p; p = proc.p_nxt) { | |
424 | if (kvm_read(p, &proc, sizeof (struct proc)) != | |
425 | sizeof (struct proc)) { | |
426 | seterr("can't read proc at %x", p); | |
427 | return (-1); | |
428 | } | |
837ee677 MK |
429 | #ifdef NEWVM |
430 | if (kvm_read(proc.p_cred, &eproc.e_pcred, | |
431 | sizeof (struct pcred)) == sizeof (struct pcred)) | |
432 | (void) kvm_read(eproc.e_pcred.pc_ucred, &eproc.e_ucred, | |
433 | sizeof (struct ucred)); | |
434 | switch(ki_op(what)) { | |
435 | ||
436 | case KINFO_PROC_PID: | |
437 | if (proc.p_pid != (pid_t)arg) | |
438 | continue; | |
439 | break; | |
440 | ||
441 | ||
442 | case KINFO_PROC_UID: | |
443 | if (eproc.e_ucred.cr_uid != (uid_t)arg) | |
444 | continue; | |
445 | break; | |
446 | ||
447 | case KINFO_PROC_RUID: | |
448 | if (eproc.e_pcred.p_ruid != (uid_t)arg) | |
449 | continue; | |
450 | break; | |
451 | } | |
452 | #else | |
41a4fbbe MT |
453 | switch(ki_op(what)) { |
454 | ||
455 | case KINFO_PROC_PID: | |
456 | if (proc.p_pid != (pid_t)arg) | |
457 | continue; | |
458 | break; | |
459 | ||
460 | ||
461 | case KINFO_PROC_UID: | |
462 | if (proc.p_uid != (uid_t)arg) | |
463 | continue; | |
464 | break; | |
465 | ||
466 | case KINFO_PROC_RUID: | |
467 | if (proc.p_ruid != (uid_t)arg) | |
468 | continue; | |
469 | break; | |
470 | } | |
837ee677 | 471 | #endif |
41a4fbbe MT |
472 | /* |
473 | * gather eproc | |
474 | */ | |
475 | eproc.e_paddr = p; | |
476 | if (kvm_read(proc.p_pgrp, &pgrp, sizeof (struct pgrp)) != | |
477 | sizeof (struct pgrp)) { | |
478 | seterr("can't read pgrp at %x", proc.p_pgrp); | |
479 | return (-1); | |
480 | } | |
481 | eproc.e_sess = pgrp.pg_session; | |
482 | eproc.e_pgid = pgrp.pg_id; | |
483 | eproc.e_jobc = pgrp.pg_jobc; | |
484 | if (kvm_read(pgrp.pg_session, &sess, sizeof (struct session)) | |
485 | != sizeof (struct session)) { | |
486 | seterr("can't read session at %x", pgrp.pg_session); | |
487 | return (-1); | |
488 | } | |
489 | if ((proc.p_flag&SCTTY) && sess.s_ttyp != NULL) { | |
490 | if (kvm_read(sess.s_ttyp, &tty, sizeof (struct tty)) | |
491 | != sizeof (struct tty)) { | |
492 | seterr("can't read tty at %x", sess.s_ttyp); | |
493 | return (-1); | |
494 | } | |
495 | eproc.e_tdev = tty.t_dev; | |
496 | eproc.e_tsess = tty.t_session; | |
497 | if (tty.t_pgrp != NULL) { | |
498 | if (kvm_read(tty.t_pgrp, &pgrp, sizeof (struct | |
499 | pgrp)) != sizeof (struct pgrp)) { | |
500 | seterr("can't read tpgrp at &x", | |
501 | tty.t_pgrp); | |
502 | return (-1); | |
503 | } | |
504 | eproc.e_tpgid = pgrp.pg_id; | |
505 | } else | |
506 | eproc.e_tpgid = -1; | |
507 | } else | |
508 | eproc.e_tdev = NODEV; | |
eeceacd9 MT |
509 | eproc.e_flag = sess.s_ttyvp ? EPROC_CTTY : 0; |
510 | if (sess.s_leader == p) | |
511 | eproc.e_flag |= EPROC_SLEADER; | |
41a4fbbe MT |
512 | if (proc.p_wmesg) |
513 | kvm_read(proc.p_wmesg, eproc.e_wmesg, WMESGLEN); | |
837ee677 MK |
514 | #ifdef NEWVM |
515 | (void) kvm_read(proc.p_vmspace, &eproc.e_vm, | |
516 | sizeof (struct vmspace)); | |
517 | eproc.e_xsize = eproc.e_xrssize = | |
518 | eproc.e_xccount = eproc.e_xswrss = 0; | |
519 | #else | |
41a4fbbe MT |
520 | if (proc.p_textp) { |
521 | kvm_read(proc.p_textp, &text, sizeof (text)); | |
522 | eproc.e_xsize = text.x_size; | |
523 | eproc.e_xrssize = text.x_rssize; | |
524 | eproc.e_xccount = text.x_ccount; | |
525 | eproc.e_xswrss = text.x_swrss; | |
526 | } else { | |
527 | eproc.e_xsize = eproc.e_xrssize = | |
528 | eproc.e_xccount = eproc.e_xswrss = 0; | |
529 | } | |
837ee677 | 530 | #endif |
41a4fbbe MT |
531 | |
532 | switch(ki_op(what)) { | |
533 | ||
534 | case KINFO_PROC_PGRP: | |
535 | if (eproc.e_pgid != (pid_t)arg) | |
536 | continue; | |
537 | break; | |
538 | ||
539 | case KINFO_PROC_TTY: | |
540 | if ((proc.p_flag&SCTTY) == 0 || | |
541 | eproc.e_tdev != (dev_t)arg) | |
542 | continue; | |
543 | break; | |
544 | } | |
545 | ||
546 | i++; | |
547 | bcopy(&proc, bp, sizeof (struct proc)); | |
548 | bp += sizeof (struct proc); | |
549 | bcopy(&eproc, bp, sizeof (struct eproc)); | |
550 | bp+= sizeof (struct eproc); | |
551 | } | |
552 | if (!doingzomb) { | |
553 | /* zombproc */ | |
469444a6 | 554 | if (kvm_read((void *) nl[X_ZOMBPROC].n_value, &p, |
41a4fbbe MT |
555 | sizeof (struct proc *)) != sizeof (struct proc *)) { |
556 | seterr("can't read zombproc"); | |
557 | return (-1); | |
558 | } | |
559 | doingzomb = 1; | |
560 | goto again; | |
561 | } | |
562 | ||
563 | return (i); | |
564 | } | |
41a4fbbe MT |
565 | |
566 | struct proc * | |
567 | kvm_nextproc() | |
568 | { | |
569 | ||
570 | if (!kvmprocbase && kvm_getprocs(0, 0) == -1) | |
571 | return (NULL); | |
572 | if (kvmprocptr >= (kvmprocbase + kvmnprocs)) { | |
573 | seterr("end of proc list"); | |
574 | return (NULL); | |
575 | } | |
576 | return((struct proc *)(kvmprocptr++)); | |
577 | } | |
578 | ||
579 | struct eproc * | |
580 | kvm_geteproc(p) | |
cc66874e | 581 | const struct proc *p; |
41a4fbbe MT |
582 | { |
583 | return ((struct eproc *)(((char *)p) + sizeof (struct proc))); | |
584 | } | |
585 | ||
586 | kvm_setproc() | |
587 | { | |
41a4fbbe MT |
588 | kvmprocptr = kvmprocbase; |
589 | } | |
590 | ||
591 | kvm_freeprocs() | |
592 | { | |
593 | ||
594 | if (kvmprocbase) { | |
595 | free(kvmprocbase); | |
596 | kvmprocbase = NULL; | |
597 | } | |
598 | } | |
599 | ||
837ee677 MK |
600 | #ifdef NEWVM |
601 | struct user * | |
602 | kvm_getu(p) | |
469444a6 | 603 | const struct proc *p; |
837ee677 MK |
604 | { |
605 | register struct kinfo_proc *kp = (struct kinfo_proc *)p; | |
606 | register int i; | |
607 | register char *up; | |
837ee677 MK |
608 | |
609 | if (kvminit == 0 && kvm_init(NULL, NULL, NULL, 0) == -1) | |
610 | return (NULL); | |
611 | if (p->p_stat == SZOMB) { | |
612 | seterr("zombie process"); | |
613 | return (NULL); | |
614 | } | |
837ee677 MK |
615 | /* |
616 | * Read u-area one page at a time for the benefit of post-mortems | |
617 | */ | |
618 | up = (char *) p->p_addr; | |
619 | for (i = 0; i < UPAGES; i++) { | |
eeceacd9 MT |
620 | if (klseek(kmem, (long)up, 0) == -1) |
621 | return (NULL); | |
837ee677 MK |
622 | if (read(kmem, user.upages[i], CLBYTES) != CLBYTES) { |
623 | seterr("cant read page %x of u of pid %d from %s", | |
624 | up, p->p_pid, kmemf); | |
625 | return(NULL); | |
626 | } | |
627 | up += CLBYTES; | |
628 | } | |
629 | pcbpf = (int) btop(p->p_addr); /* what should this be really? */ | |
630 | /* | |
631 | * Conjure up a physical address for the arguments. | |
632 | */ | |
633 | argaddr0 = argaddr1 = 0; | |
634 | #ifdef hp300 | |
635 | if (kp->kp_eproc.e_vm.vm_pmap.pm_ptab) { | |
469444a6 MK |
636 | struct pte pte[CLSIZE*2]; |
637 | ||
eeceacd9 | 638 | if (klseek(kmem, |
837ee677 | 639 | (long)&kp->kp_eproc.e_vm.vm_pmap.pm_ptab |
eeceacd9 MT |
640 | [btoc(USRSTACK-CLBYTES*2)], 0) == -1) |
641 | return (NULL); | |
837ee677 | 642 | if (read(kmem, (char *)&pte, sizeof(pte)) == sizeof(pte)) { |
469444a6 | 643 | #if CLBYTES < 2048 |
837ee677 | 644 | argaddr0 = ctob(pftoc(pte[CLSIZE*0].pg_pfnum)); |
469444a6 | 645 | #endif |
837ee677 MK |
646 | argaddr1 = ctob(pftoc(pte[CLSIZE*1].pg_pfnum)); |
647 | } | |
648 | } | |
649 | kp->kp_eproc.e_vm.vm_rssize = | |
650 | kp->kp_eproc.e_vm.vm_pmap.pm_stats.resident_count; /* XXX */ | |
651 | #endif | |
652 | return(&user.user); | |
653 | } | |
654 | #else | |
41a4fbbe MT |
655 | struct user * |
656 | kvm_getu(p) | |
cc66874e | 657 | const struct proc *p; |
41a4fbbe MT |
658 | { |
659 | struct pte *pteaddr, apte; | |
bd6478f9 | 660 | struct pte arguutl[HIGHPAGES+(CLSIZE*2)]; |
41a4fbbe MT |
661 | register int i; |
662 | int ncl; | |
663 | ||
664 | if (kvminit == 0 && kvm_init(NULL, NULL, NULL, 0) == -1) | |
665 | return (NULL); | |
0e005c87 MT |
666 | if (p->p_stat == SZOMB) { |
667 | seterr("zombie process"); | |
41a4fbbe | 668 | return (NULL); |
0e005c87 | 669 | } |
41a4fbbe | 670 | if ((p->p_flag & SLOAD) == 0) { |
0e005c87 MT |
671 | if (swap < 0) { |
672 | seterr("no swap"); | |
41a4fbbe | 673 | return (NULL); |
0e005c87 | 674 | } |
41a4fbbe MT |
675 | (void) lseek(swap, (long)dtob(p->p_swaddr), 0); |
676 | if (read(swap, (char *)&user.user, sizeof (struct user)) != | |
677 | sizeof (struct user)) { | |
837ee677 | 678 | seterr("can't read u for pid %d from %s", |
41a4fbbe MT |
679 | p->p_pid, swapf); |
680 | return (NULL); | |
681 | } | |
682 | pcbpf = 0; | |
0e005c87 MT |
683 | argaddr0 = 0; |
684 | argaddr1 = 0; | |
41a4fbbe MT |
685 | return (&user.user); |
686 | } | |
687 | pteaddr = &Usrptmap[btokmx(p->p_p0br) + p->p_szpt - 1]; | |
eeceacd9 MT |
688 | if (klseek(kmem, (long)pteaddr, 0) == -1) |
689 | return -1; | |
41a4fbbe MT |
690 | if (read(kmem, (char *)&apte, sizeof(apte)) != sizeof(apte)) { |
691 | seterr("can't read indir pte to get u for pid %d from %s", | |
692 | p->p_pid, kmemf); | |
693 | return (NULL); | |
694 | } | |
bd6478f9 | 695 | lseek(mem, (long)ctob(pftoc(apte.pg_pfnum+1)) - sizeof(arguutl), 0); |
41a4fbbe MT |
696 | if (read(mem, (char *)arguutl, sizeof(arguutl)) != sizeof(arguutl)) { |
697 | seterr("can't read page table for u of pid %d from %s", | |
698 | p->p_pid, memf); | |
699 | return (NULL); | |
700 | } | |
701 | if (arguutl[0].pg_fod == 0 && arguutl[0].pg_pfnum) | |
bd6478f9 | 702 | argaddr0 = ctob(pftoc(arguutl[0].pg_pfnum)); |
41a4fbbe | 703 | else |
0e005c87 MT |
704 | argaddr0 = 0; |
705 | if (arguutl[CLSIZE*1].pg_fod == 0 && arguutl[CLSIZE*1].pg_pfnum) | |
bd6478f9 | 706 | argaddr1 = ctob(pftoc(arguutl[CLSIZE*1].pg_pfnum)); |
0e005c87 MT |
707 | else |
708 | argaddr1 = 0; | |
709 | pcbpf = arguutl[CLSIZE*2].pg_pfnum; | |
bd6478f9 | 710 | ncl = (sizeof (struct user) + CLBYTES - 1) / CLBYTES; |
41a4fbbe MT |
711 | while (--ncl >= 0) { |
712 | i = ncl * CLSIZE; | |
bd6478f9 KB |
713 | lseek(mem, |
714 | (long)ctob(pftoc(arguutl[(CLSIZE*2)+i].pg_pfnum)), 0); | |
715 | if (read(mem, user.upages[i], CLBYTES) != CLBYTES) { | |
41a4fbbe | 716 | seterr("can't read page %d of u of pid %d from %s", |
bd6478f9 | 717 | arguutl[(CLSIZE*2)+i].pg_pfnum, p->p_pid, memf); |
41a4fbbe MT |
718 | return(NULL); |
719 | } | |
720 | } | |
721 | return (&user.user); | |
722 | } | |
837ee677 | 723 | #endif |
41a4fbbe MT |
724 | |
725 | char * | |
726 | kvm_getargs(p, up) | |
cc66874e KB |
727 | const struct proc *p; |
728 | const struct user *up; | |
41a4fbbe | 729 | { |
3c4639f9 | 730 | static char cmdbuf[CLBYTES*2]; |
41a4fbbe | 731 | union { |
bd6478f9 KB |
732 | char argc[CLBYTES*2]; |
733 | int argi[CLBYTES*2/sizeof (int)]; | |
41a4fbbe MT |
734 | } argspac; |
735 | register char *cp; | |
736 | register int *ip; | |
737 | char c; | |
738 | int nbad; | |
837ee677 | 739 | #ifndef NEWVM |
41a4fbbe | 740 | struct dblock db; |
837ee677 | 741 | #endif |
c6bc5b9d | 742 | const char *file; |
837ee677 | 743 | int stkoff = 0; |
41a4fbbe | 744 | |
837ee677 | 745 | #if defined(NEWVM) && defined(hp300) |
469444a6 | 746 | stkoff = 20; /* XXX for sigcode */ |
837ee677 | 747 | #endif |
0e005c87 | 748 | if (up == NULL || p->p_pid == 0 || p->p_pid == 2) |
41a4fbbe | 749 | goto retucomm; |
0e005c87 | 750 | if ((p->p_flag & SLOAD) == 0 || argaddr1 == 0) { |
837ee677 MK |
751 | #ifdef NEWVM |
752 | goto retucomm; /* XXX for now */ | |
753 | #else | |
bd6478f9 | 754 | if (swap < 0 || p->p_ssize == 0) |
41a4fbbe MT |
755 | goto retucomm; |
756 | vstodb(0, CLSIZE, &up->u_smap, &db, 1); | |
757 | (void) lseek(swap, (long)dtob(db.db_base), 0); | |
bd6478f9 KB |
758 | if (read(swap, (char *)&argspac.argc[CLBYTES], CLBYTES) |
759 | != CLBYTES) | |
0e005c87 MT |
760 | goto bad; |
761 | vstodb(1, CLSIZE, &up->u_smap, &db, 1); | |
762 | (void) lseek(swap, (long)dtob(db.db_base), 0); | |
bd6478f9 | 763 | if (read(swap, (char *)&argspac.argc[0], CLBYTES) != CLBYTES) |
41a4fbbe MT |
764 | goto bad; |
765 | file = swapf; | |
837ee677 | 766 | #endif |
41a4fbbe | 767 | } else { |
0e005c87 MT |
768 | if (argaddr0) { |
769 | lseek(mem, (long)argaddr0, 0); | |
bd6478f9 | 770 | if (read(mem, (char *)&argspac, CLBYTES) != CLBYTES) |
0e005c87 MT |
771 | goto bad; |
772 | } else | |
bd6478f9 | 773 | bzero(&argspac, CLBYTES); |
0e005c87 | 774 | lseek(mem, (long)argaddr1, 0); |
bd6478f9 | 775 | if (read(mem, &argspac.argc[CLBYTES], CLBYTES) != CLBYTES) |
41a4fbbe | 776 | goto bad; |
469444a6 | 777 | file = (char *) memf; |
41a4fbbe | 778 | } |
bd6478f9 | 779 | ip = &argspac.argi[CLBYTES*2/sizeof (int)]; |
469444a6 | 780 | ip -= 2; /* last arg word and .long 0 */ |
837ee677 | 781 | ip -= stkoff / sizeof (int); |
41a4fbbe MT |
782 | while (*--ip) { |
783 | if (ip == argspac.argi) | |
784 | goto retucomm; | |
785 | } | |
786 | *(char *)ip = ' '; | |
787 | ip++; | |
788 | nbad = 0; | |
837ee677 | 789 | for (cp = (char *)ip; cp < &argspac.argc[CLBYTES*2-stkoff]; cp++) { |
41a4fbbe MT |
790 | c = *cp & 0177; |
791 | if (c == 0) | |
792 | *cp = ' '; | |
793 | else if (c < ' ' || c > 0176) { | |
794 | if (++nbad >= 5*(0+1)) { /* eflg -> 0 XXX */ | |
795 | *cp++ = ' '; | |
796 | break; | |
797 | } | |
798 | *cp = '?'; | |
799 | } else if (0 == 0 && c == '=') { /* eflg -> 0 XXX */ | |
800 | while (*--cp != ' ') | |
801 | if (cp <= (char *)ip) | |
802 | break; | |
803 | break; | |
804 | } | |
805 | } | |
806 | *cp = 0; | |
807 | while (*--cp == ' ') | |
808 | *cp = 0; | |
809 | cp = (char *)ip; | |
bd6478f9 | 810 | (void) strncpy(cmdbuf, cp, &argspac.argc[CLBYTES*2] - cp); |
41a4fbbe MT |
811 | if (cp[0] == '-' || cp[0] == '?' || cp[0] <= ' ') { |
812 | (void) strcat(cmdbuf, " ("); | |
813 | (void) strncat(cmdbuf, p->p_comm, sizeof(p->p_comm)); | |
814 | (void) strcat(cmdbuf, ")"); | |
815 | } | |
816 | return (cmdbuf); | |
817 | ||
818 | bad: | |
837ee677 | 819 | seterr("error locating command name for pid %d from %s", |
41a4fbbe MT |
820 | p->p_pid, file); |
821 | retucomm: | |
822 | (void) strcpy(cmdbuf, " ("); | |
823 | (void) strncat(cmdbuf, p->p_comm, sizeof (p->p_comm)); | |
824 | (void) strcat(cmdbuf, ")"); | |
825 | return (cmdbuf); | |
826 | } | |
827 | ||
828 | ||
829 | static | |
830 | getkvars() | |
831 | { | |
3c4639f9 MT |
832 | int ret; |
833 | static nlisterr(); | |
834 | ||
835 | if ((ret = kvm_nlist(nl)) == -1) | |
41a4fbbe | 836 | return (-1); |
3c4639f9 MT |
837 | else if (ret > 0) |
838 | nlisterr(nl); | |
41a4fbbe MT |
839 | if (deadkernel) { |
840 | /* We must do the sys map first because klseek uses it */ | |
841 | long addr; | |
bd6478f9 KB |
842 | #if defined(hp300) |
843 | addr = (long) nl[X_LOWRAM].n_value; | |
844 | (void) lseek(kmem, addr, 0); | |
845 | if (read(kmem, (char *) &lowram, sizeof (lowram)) | |
846 | != sizeof (lowram)) { | |
847 | seterr("can't read lowram"); | |
848 | return (-1); | |
849 | } | |
850 | lowram = btop(lowram); | |
837ee677 MK |
851 | Sysseg = (struct ste *) malloc(NBPG); |
852 | if (Sysseg == NULL) { | |
853 | seterr("out of space for Sysseg"); | |
854 | return (-1); | |
855 | } | |
856 | addr = (long) nl[X_SYSSEG].n_value; | |
857 | (void) lseek(kmem, addr, 0); | |
858 | read(kmem, (char *)&addr, sizeof(addr)); | |
859 | (void) lseek(kmem, (long)addr, 0); | |
860 | if (read(kmem, (char *) Sysseg, NBPG) != NBPG) { | |
861 | seterr("can't read Sysseg"); | |
862 | return (-1); | |
863 | } | |
bd6478f9 | 864 | #endif |
41a4fbbe | 865 | } |
469444a6 | 866 | if (kvm_read((void *) nl[X_NSWAP].n_value, &nswap, sizeof (long)) != |
41a4fbbe MT |
867 | sizeof (long)) { |
868 | seterr("can't read nswap"); | |
869 | return (-1); | |
870 | } | |
469444a6 | 871 | if (kvm_read((void *) nl[X_DMMIN].n_value, &dmmin, sizeof (long)) != |
41a4fbbe MT |
872 | sizeof (long)) { |
873 | seterr("can't read dmmin"); | |
874 | return (-1); | |
875 | } | |
469444a6 | 876 | if (kvm_read((void *) nl[X_DMMAX].n_value, &dmmax, sizeof (long)) != |
41a4fbbe MT |
877 | sizeof (long)) { |
878 | seterr("can't read dmmax"); | |
879 | return (-1); | |
880 | } | |
881 | return (0); | |
882 | } | |
883 | ||
3c4639f9 MT |
884 | static |
885 | nlisterr(nl) | |
886 | struct nlist nl[]; | |
887 | { | |
888 | int i; | |
889 | ||
890 | fprintf(stderr, "kvm_nlist: can't find following names:"); | |
891 | for (i = 0; nl[i].n_name[0] != '\0'; i++) | |
892 | if (nl[i].n_value == 0) | |
893 | fprintf(stderr, " %s", nl[i].n_name); | |
894 | fprintf(stderr, ": continuing...\n"); | |
895 | } | |
896 | ||
897 | ||
41a4fbbe | 898 | kvm_read(loc, buf, len) |
469444a6 MK |
899 | void *loc; |
900 | void *buf; | |
41a4fbbe | 901 | { |
0e005c87 MT |
902 | if (kvmfilesopen == 0 && kvm_openfiles(NULL, NULL, NULL) == -1) |
903 | return (-1); | |
bd6478f9 | 904 | if (iskva(loc)) { |
eeceacd9 MT |
905 | if (klseek(kmem, (off_t) loc, 0) == -1) |
906 | return -1; | |
41a4fbbe | 907 | if (read(kmem, buf, len) != len) { |
837ee677 | 908 | seterr("error reading kmem at %x", loc); |
41a4fbbe MT |
909 | return (-1); |
910 | } | |
911 | } else { | |
d0e536aa | 912 | lseek(mem, (off_t) loc, 0); |
41a4fbbe | 913 | if (read(mem, buf, len) != len) { |
837ee677 | 914 | seterr("error reading mem at %x", loc); |
41a4fbbe MT |
915 | return (-1); |
916 | } | |
917 | } | |
918 | return (len); | |
919 | } | |
920 | ||
eeceacd9 | 921 | static |
41a4fbbe MT |
922 | klseek(fd, loc, off) |
923 | int fd; | |
0e005c87 | 924 | off_t loc; |
41a4fbbe MT |
925 | int off; |
926 | { | |
0e005c87 | 927 | |
41a4fbbe MT |
928 | if (deadkernel) { |
929 | if ((loc = vtophys(loc)) == -1) | |
eeceacd9 | 930 | return -1; |
41a4fbbe | 931 | } |
eeceacd9 MT |
932 | (void)lseek(fd, (off_t)loc, off); |
933 | return (0); | |
41a4fbbe MT |
934 | } |
935 | ||
837ee677 | 936 | #ifndef NEWVM |
41a4fbbe MT |
937 | /* |
938 | * Given a base/size pair in virtual swap area, | |
939 | * return a physical base/size pair which is the | |
940 | * (largest) initial, physically contiguous block. | |
941 | */ | |
cc66874e | 942 | static void |
41a4fbbe MT |
943 | vstodb(vsbase, vssize, dmp, dbp, rev) |
944 | register int vsbase; | |
945 | int vssize; | |
946 | struct dmap *dmp; | |
947 | register struct dblock *dbp; | |
948 | { | |
949 | register int blk = dmmin; | |
950 | register swblk_t *ip = dmp->dm_map; | |
951 | ||
952 | vsbase = ctod(vsbase); | |
953 | vssize = ctod(vssize); | |
954 | if (vsbase < 0 || vsbase + vssize > dmp->dm_size) | |
955 | /*panic("vstodb")*/; | |
956 | while (vsbase >= blk) { | |
957 | vsbase -= blk; | |
958 | if (blk < dmmax) | |
959 | blk *= 2; | |
960 | ip++; | |
961 | } | |
962 | if (*ip <= 0 || *ip + blk > nswap) | |
963 | /*panic("vstodb")*/; | |
964 | dbp->db_size = MIN(vssize, blk - vsbase); | |
965 | dbp->db_base = *ip + (rev ? blk - (vsbase + dbp->db_size) : vsbase); | |
966 | } | |
837ee677 MK |
967 | #endif |
968 | ||
969 | #ifdef NEWVM | |
970 | static off_t | |
971 | vtophys(loc) | |
972 | long loc; | |
973 | { | |
974 | off_t newloc = (off_t) -1; | |
975 | #ifdef hp300 | |
976 | int p, ste, pte; | |
41a4fbbe | 977 | |
837ee677 MK |
978 | ste = *(int *)&Sysseg[loc >> SG_ISHIFT]; |
979 | if ((ste & SG_V) == 0) { | |
eeceacd9 | 980 | seterr("vtophys: segment not valid (%x)", ste); |
837ee677 MK |
981 | return((off_t) -1); |
982 | } | |
983 | p = btop(loc & SG_PMASK); | |
984 | newloc = (ste & SG_FRAME) + (p * sizeof(struct pte)); | |
985 | (void) lseek(kmem, (long)(newloc-(off_t)ptob(lowram)), 0); | |
986 | if (read(kmem, (char *)&pte, sizeof pte) != sizeof pte) { | |
987 | seterr("vtophys: cannot locate pte"); | |
988 | return((off_t) -1); | |
989 | } | |
990 | newloc = pte & PG_FRAME; | |
991 | if (pte == PG_NV || newloc < (off_t)ptob(lowram)) { | |
992 | seterr("vtophys: page not valid"); | |
993 | return((off_t) -1); | |
994 | } | |
995 | newloc = (newloc - (off_t)ptob(lowram)) + (loc & PGOFSET); | |
996 | #endif | |
997 | return((off_t) newloc); | |
998 | } | |
999 | #else | |
41a4fbbe MT |
1000 | static off_t |
1001 | vtophys(loc) | |
1002 | long loc; | |
1003 | { | |
bd6478f9 | 1004 | int p; |
41a4fbbe | 1005 | off_t newloc; |
bd6478f9 | 1006 | register struct pte *pte; |
41a4fbbe MT |
1007 | |
1008 | newloc = loc & ~KERNBASE; | |
1009 | p = btop(newloc); | |
bd6478f9 | 1010 | #if defined(vax) || defined(tahoe) |
41a4fbbe MT |
1011 | if ((loc & KERNBASE) == 0) { |
1012 | seterr("vtophys: translating non-kernel address"); | |
1013 | return((off_t) -1); | |
1014 | } | |
bd6478f9 | 1015 | #endif |
41a4fbbe MT |
1016 | if (p >= Syssize) { |
1017 | seterr("vtophys: page out of bound (%d>=%d)", p, Syssize); | |
1018 | return((off_t) -1); | |
1019 | } | |
bd6478f9 KB |
1020 | pte = &Sysmap[p]; |
1021 | if (pte->pg_v == 0 && (pte->pg_fod || pte->pg_pfnum == 0)) { | |
41a4fbbe MT |
1022 | seterr("vtophys: page not valid"); |
1023 | return((off_t) -1); | |
1024 | } | |
bd6478f9 KB |
1025 | #if defined(hp300) |
1026 | if (pte->pg_pfnum < lowram) { | |
1027 | seterr("vtophys: non-RAM page (%d<%d)", pte->pg_pfnum, lowram); | |
1028 | return((off_t) -1); | |
1029 | } | |
1030 | #endif | |
1031 | loc = (long) (ptob(pftoc(pte->pg_pfnum)) + (loc & PGOFSET)); | |
41a4fbbe MT |
1032 | return(loc); |
1033 | } | |
837ee677 | 1034 | #endif |
41a4fbbe MT |
1035 | |
1036 | #include <varargs.h> | |
47587ec1 | 1037 | static char errbuf[_POSIX2_LINE_MAX]; |
41a4fbbe | 1038 | |
cc66874e | 1039 | static void |
41a4fbbe MT |
1040 | seterr(va_alist) |
1041 | va_dcl | |
1042 | { | |
1043 | char *fmt; | |
1044 | va_list ap; | |
1045 | ||
1046 | va_start(ap); | |
1047 | fmt = va_arg(ap, char *); | |
469444a6 | 1048 | (void) vsnprintf(errbuf, _POSIX2_LINE_MAX, fmt, ap); |
41a4fbbe MT |
1049 | va_end(ap); |
1050 | } | |
1051 | ||
cc66874e | 1052 | static void |
41a4fbbe MT |
1053 | setsyserr(va_alist) |
1054 | va_dcl | |
1055 | { | |
1056 | char *fmt, *cp; | |
1057 | va_list ap; | |
bd6478f9 | 1058 | extern int errno; |
41a4fbbe MT |
1059 | |
1060 | va_start(ap); | |
1061 | fmt = va_arg(ap, char *); | |
469444a6 | 1062 | (void) vsnprintf(errbuf, _POSIX2_LINE_MAX, fmt, ap); |
41a4fbbe MT |
1063 | for (cp=errbuf; *cp; cp++) |
1064 | ; | |
469444a6 | 1065 | snprintf(cp, _POSIX2_LINE_MAX - (cp - errbuf), ": %s", strerror(errno)); |
41a4fbbe MT |
1066 | va_end(ap); |
1067 | } | |
1068 | ||
1069 | char * | |
1070 | kvm_geterr() | |
1071 | { | |
41a4fbbe MT |
1072 | return (errbuf); |
1073 | } |