Annotation of src/usr.bin/kdump/kdump.c, Revision 1.44
1.44 ! tedu 1: /* $OpenBSD: kdump.c,v 1.43 2010/06/29 20:30:33 guenther Exp $ */
1.4 deraadt 2:
1.1 deraadt 3: /*-
4: * Copyright (c) 1988, 1993
5: * The Regents of the University of California. All rights reserved.
6: *
7: * Redistribution and use in source and binary forms, with or without
8: * modification, are permitted provided that the following conditions
9: * are met:
10: * 1. Redistributions of source code must retain the above copyright
11: * notice, this list of conditions and the following disclaimer.
12: * 2. Redistributions in binary form must reproduce the above copyright
13: * notice, this list of conditions and the following disclaimer in the
14: * documentation and/or other materials provided with the distribution.
1.21 millert 15: * 3. Neither the name of the University nor the names of its contributors
1.1 deraadt 16: * may be used to endorse or promote products derived from this software
17: * without specific prior written permission.
18: *
19: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29: * SUCH DAMAGE.
30: */
31:
32: #include <sys/param.h>
33: #include <sys/time.h>
34: #include <sys/uio.h>
35: #include <sys/ktrace.h>
36: #include <sys/ioctl.h>
37: #include <sys/ptrace.h>
1.28 deraadt 38: #include <sys/sysctl.h>
1.1 deraadt 39: #define _KERNEL
40: #include <sys/errno.h>
41: #undef _KERNEL
42:
1.33 tedu 43: #include <ctype.h>
1.1 deraadt 44: #include <err.h>
45: #include <signal.h>
46: #include <stdio.h>
47: #include <stdlib.h>
48: #include <string.h>
49: #include <unistd.h>
50: #include <vis.h>
51:
52: #include "ktrace.h"
1.22 deraadt 53: #include "kdump.h"
1.12 espie 54: #include "extern.h"
1.1 deraadt 55:
1.31 tedu 56: int timestamp, decimal, iohex, fancy = 1, tail, maxdata;
1.1 deraadt 57: char *tracefile = DEF_TRACEFILE;
58: struct ktr_header ktr_header;
1.17 deraadt 59: pid_t pid = -1;
1.1 deraadt 60:
61: #define eqs(s1, s2) (strcmp((s1), (s2)) == 0)
62:
63: #include <sys/syscall.h>
64:
1.25 mickey 65: #include <compat/bsdos/bsdos_syscall.h>
66: #include <compat/freebsd/freebsd_syscall.h>
67: #include <compat/ibcs2/ibcs2_syscall.h>
68: #include <compat/linux/linux_syscall.h>
69: #include <compat/sunos/sunos_syscall.h>
70: #include <compat/svr4/svr4_syscall.h>
1.1 deraadt 71:
72: #define KTRACE
1.19 mickey 73: #define PTRACE
1.7 deraadt 74: #define NFSCLIENT
75: #define NFSSERVER
76: #define SYSVSEM
77: #define SYSVMSG
78: #define SYSVSHM
79: #define LFS
1.30 miod 80: #define RTHREADS
1.25 mickey 81: #include <kern/syscalls.c>
1.1 deraadt 82:
1.25 mickey 83: #include <compat/bsdos/bsdos_syscalls.c>
84: #include <compat/freebsd/freebsd_syscalls.c>
85: #include <compat/ibcs2/ibcs2_syscalls.c>
86: #include <compat/linux/linux_syscalls.c>
87: #include <compat/sunos/sunos_syscalls.c>
88: #include <compat/svr4/svr4_syscalls.c>
1.1 deraadt 89: #undef KTRACE
1.19 mickey 90: #undef PTRACE
1.7 deraadt 91: #undef NFSCLIENT
92: #undef NFSSERVER
93: #undef SYSVSEM
94: #undef SYSVMSG
95: #undef SYSVSHM
96: #undef LFS
1.30 miod 97: #undef RTHREADS
1.1 deraadt 98:
99: struct emulation {
100: char *name; /* Emulation name */
101: char **sysnames; /* Array of system call names */
102: int nsysnames; /* Number of */
103: };
104:
105: static struct emulation emulations[] = {
1.9 deraadt 106: { "native", syscallnames, SYS_MAXSYSCALL },
107: { "ibcs2", ibcs2_syscallnames, IBCS2_SYS_MAXSYSCALL },
108: { "linux", linux_syscallnames, LINUX_SYS_MAXSYSCALL },
109: { "sunos", sunos_syscallnames, SUNOS_SYS_MAXSYSCALL },
110: { "svr4", svr4_syscallnames, SVR4_SYS_MAXSYSCALL },
111: { "bsdos", bsdos_syscallnames, BSDOS_SYS_MAXSYSCALL },
112: { "freebsd", freebsd_syscallnames, FREEBSD_SYS_MAXSYSCALL },
113: { NULL, NULL, NULL }
1.1 deraadt 114: };
115:
116: struct emulation *current;
117:
118:
119: static char *ptrace_ops[] = {
120: "PT_TRACE_ME", "PT_READ_I", "PT_READ_D", "PT_READ_U",
121: "PT_WRITE_I", "PT_WRITE_D", "PT_WRITE_U", "PT_CONTINUE",
1.15 art 122: "PT_KILL", "PT_ATTACH", "PT_DETACH", "PT_IO",
1.1 deraadt 123: };
124:
1.37 tedu 125: static int fread_tail(void *, size_t, size_t);
1.13 millert 126: static void dumpheader(struct ktr_header *);
127: static void ktrcsw(struct ktr_csw *);
1.37 tedu 128: static void ktremul(char *, size_t);
129: static void ktrgenio(struct ktr_genio *, size_t);
130: static void ktrnamei(const char *, size_t);
1.13 millert 131: static void ktrpsig(struct ktr_psig *);
132: static void ktrsyscall(struct ktr_syscall *);
133: static void ktrsysret(struct ktr_sysret *);
134: static void setemul(const char *);
135: static void usage(void);
1.12 espie 136:
1.1 deraadt 137: int
1.17 deraadt 138: main(int argc, char *argv[])
1.1 deraadt 139: {
1.37 tedu 140: int ch, silent;
141: size_t ktrlen, size;
1.17 deraadt 142: int trpoints = ALL_POINTS;
1.12 espie 143: void *m;
1.1 deraadt 144:
1.3 deraadt 145: current = &emulations[0]; /* native */
1.1 deraadt 146:
1.31 tedu 147: while ((ch = getopt(argc, argv, "e:f:dlm:nRp:Tt:xX")) != -1)
1.1 deraadt 148: switch (ch) {
149: case 'e':
150: setemul(optarg);
151: break;
152: case 'f':
153: tracefile = optarg;
154: break;
155: case 'd':
156: decimal = 1;
157: break;
158: case 'l':
159: tail = 1;
160: break;
161: case 'm':
162: maxdata = atoi(optarg);
163: break;
164: case 'n':
165: fancy = 0;
166: break;
1.17 deraadt 167: case 'p':
168: pid = atoi(optarg);
169: break;
1.1 deraadt 170: case 'R':
171: timestamp = 2; /* relative timestamp */
172: break;
173: case 'T':
174: timestamp = 1;
175: break;
176: case 't':
177: trpoints = getpoints(optarg);
178: if (trpoints < 0)
179: errx(1, "unknown trace point in %s", optarg);
180: break;
1.31 tedu 181: case 'x':
182: iohex = 1;
183: break;
184: case 'X':
185: iohex = 2;
186: break;
1.1 deraadt 187: default:
188: usage();
189: }
1.5 deraadt 190: if (argc > optind)
1.1 deraadt 191: usage();
192:
1.37 tedu 193: m = malloc(size = 1025);
1.1 deraadt 194: if (m == NULL)
1.37 tedu 195: err(1, NULL);
1.1 deraadt 196: if (!freopen(tracefile, "r", stdin))
197: err(1, "%s", tracefile);
198: while (fread_tail(&ktr_header, sizeof(struct ktr_header), 1)) {
1.17 deraadt 199: silent = 0;
200: if (pid != -1 && pid != ktr_header.ktr_pid)
201: silent = 1;
202: if (silent == 0 && trpoints & (1<<ktr_header.ktr_type))
1.1 deraadt 203: dumpheader(&ktr_header);
1.37 tedu 204: ktrlen = ktr_header.ktr_len;
1.1 deraadt 205: if (ktrlen > size) {
1.23 tedu 206: void *newm;
207:
208: newm = realloc(m, ktrlen+1);
209: if (newm == NULL)
1.37 tedu 210: err(1, NULL);
1.23 tedu 211: m = newm;
1.1 deraadt 212: size = ktrlen;
213: }
214: if (ktrlen && fread_tail(m, ktrlen, 1) == 0)
215: errx(1, "data too short");
1.17 deraadt 216: if (silent)
217: continue;
1.1 deraadt 218: if ((trpoints & (1<<ktr_header.ktr_type)) == 0)
219: continue;
220: switch (ktr_header.ktr_type) {
221: case KTR_SYSCALL:
222: ktrsyscall((struct ktr_syscall *)m);
223: break;
224: case KTR_SYSRET:
225: ktrsysret((struct ktr_sysret *)m);
226: break;
227: case KTR_NAMEI:
228: ktrnamei(m, ktrlen);
229: break;
230: case KTR_GENIO:
231: ktrgenio((struct ktr_genio *)m, ktrlen);
232: break;
233: case KTR_PSIG:
234: ktrpsig((struct ktr_psig *)m);
235: break;
236: case KTR_CSW:
237: ktrcsw((struct ktr_csw *)m);
238: break;
239: case KTR_EMUL:
240: ktremul(m, ktrlen);
241: break;
242: }
243: if (tail)
244: (void)fflush(stdout);
245: }
1.12 espie 246: exit(0);
1.1 deraadt 247: }
248:
1.12 espie 249: static int
1.37 tedu 250: fread_tail(void *buf, size_t size, size_t num)
1.1 deraadt 251: {
252: int i;
253:
254: while ((i = fread(buf, size, num, stdin)) == 0 && tail) {
255: (void)sleep(1);
256: clearerr(stdin);
257: }
258: return (i);
259: }
260:
1.12 espie 261: static void
1.17 deraadt 262: dumpheader(struct ktr_header *kth)
1.1 deraadt 263: {
1.17 deraadt 264: static struct timeval prevtime;
1.1 deraadt 265: char unknown[64], *type;
266: struct timeval temp;
267:
268: switch (kth->ktr_type) {
269: case KTR_SYSCALL:
270: type = "CALL";
271: break;
272: case KTR_SYSRET:
273: type = "RET ";
274: break;
275: case KTR_NAMEI:
276: type = "NAMI";
277: break;
278: case KTR_GENIO:
279: type = "GIO ";
280: break;
281: case KTR_PSIG:
282: type = "PSIG";
283: break;
284: case KTR_CSW:
285: type = "CSW";
286: break;
287: case KTR_EMUL:
288: type = "EMUL";
289: break;
290: default:
1.17 deraadt 291: (void)snprintf(unknown, sizeof unknown, "UNKNOWN(%d)",
292: kth->ktr_type);
1.1 deraadt 293: type = unknown;
294: }
295:
1.16 mpech 296: (void)printf("%6ld %-8.*s ", (long)kth->ktr_pid, MAXCOMLEN,
297: kth->ktr_comm);
1.1 deraadt 298: if (timestamp) {
299: if (timestamp == 2) {
300: timersub(&kth->ktr_time, &prevtime, &temp);
301: prevtime = kth->ktr_time;
302: } else
303: temp = kth->ktr_time;
304: (void)printf("%ld.%06ld ", temp.tv_sec, temp.tv_usec);
305: }
306: (void)printf("%s ", type);
307: }
308:
1.12 espie 309: static void
1.17 deraadt 310: ioctldecode(u_long cmd)
1.2 deraadt 311: {
312: char dirbuf[4], *dir = dirbuf;
313:
1.6 deraadt 314: if (cmd & IOC_IN)
315: *dir++ = 'W';
1.2 deraadt 316: if (cmd & IOC_OUT)
317: *dir++ = 'R';
318: *dir = '\0';
319:
1.33 tedu 320: printf(decimal ? ",_IO%s('%c',%lu" : ",_IO%s('%c',%#lx",
321: dirbuf, (int)((cmd >> 8) & 0xff), cmd & 0xff);
1.2 deraadt 322: if ((cmd & IOC_VOID) == 0)
1.34 tedu 323: printf(decimal ? ",%lu)" : ",%#lx)", (cmd >> 16) & 0xff);
1.2 deraadt 324: else
325: printf(")");
326: }
1.1 deraadt 327:
1.12 espie 328: static void
1.17 deraadt 329: ktrsyscall(struct ktr_syscall *ktr)
1.1 deraadt 330: {
1.12 espie 331: int argsize = ktr->ktr_argsize;
332: register_t *ap;
1.1 deraadt 333:
334: if (ktr->ktr_code >= current->nsysnames || ktr->ktr_code < 0)
335: (void)printf("[%d]", ktr->ktr_code);
336: else
337: (void)printf("%s", current->sysnames[ktr->ktr_code]);
338: ap = (register_t *)((char *)ktr + sizeof(struct ktr_syscall));
1.27 mickey 339: (void)putchar('(');
1.1 deraadt 340: if (argsize) {
1.27 mickey 341: char c = '\0';
1.1 deraadt 342: if (fancy) {
343: if (ktr->ktr_code == SYS_ioctl) {
1.12 espie 344: const char *cp;
1.17 deraadt 345:
1.1 deraadt 346: if (decimal)
1.27 mickey 347: (void)printf("%ld", (long)*ap);
1.1 deraadt 348: else
1.27 mickey 349: (void)printf("%#lx", (long)*ap);
1.1 deraadt 350: ap++;
351: argsize -= sizeof(register_t);
352: if ((cp = ioctlname(*ap)) != NULL)
353: (void)printf(",%s", cp);
1.2 deraadt 354: else
355: ioctldecode(*ap);
1.1 deraadt 356: c = ',';
357: ap++;
358: argsize -= sizeof(register_t);
1.27 mickey 359: } else if (ktr->ktr_code == SYS___sysctl) {
360: int *np, n;
361:
362: n = ap[1];
1.28 deraadt 363: if (n > CTL_MAXNAME)
364: n = CTL_MAXNAME;
1.27 mickey 365: np = (int *)(ap + 6);
366: for (; n--; np++) {
367: if (c)
368: putchar(c);
369: printf("%d", *np);
370: c = '.';
371: }
372:
373: c = ',';
374: ap += 2;
375: argsize -= 2 * sizeof(register_t);
1.1 deraadt 376: } else if (ktr->ktr_code == SYS_ptrace) {
1.24 miod 377: if (*ap >= 0 && *ap <
1.1 deraadt 378: sizeof(ptrace_ops) / sizeof(ptrace_ops[0]))
1.27 mickey 379: (void)printf("%s", ptrace_ops[*ap]);
1.24 miod 380: else switch(*ap) {
381: #ifdef PT_GETFPREGS
382: case PT_GETFPREGS:
1.27 mickey 383: (void)printf("PT_GETFPREGS");
1.24 miod 384: break;
385: #endif
386: case PT_GETREGS:
1.27 mickey 387: (void)printf("PT_GETREGS");
1.24 miod 388: break;
389: #ifdef PT_SETFPREGS
390: case PT_SETFPREGS:
1.27 mickey 391: (void)printf("PT_SETFPREGS");
1.24 miod 392: break;
393: #endif
394: case PT_SETREGS:
1.27 mickey 395: (void)printf("PT_SETREGS");
1.24 miod 396: break;
397: #ifdef PT_STEP
398: case PT_STEP:
1.27 mickey 399: (void)printf("PT_STEP");
1.24 miod 400: break;
401: #endif
402: #ifdef PT_WCOOKIE
403: case PT_WCOOKIE:
1.27 mickey 404: (void)printf("PT_WCOOKIE");
1.24 miod 405: break;
406: #endif
407: default:
1.27 mickey 408: (void)printf("%ld", (long)*ap);
1.24 miod 409: break;
410: }
1.1 deraadt 411: c = ',';
412: ap++;
413: argsize -= sizeof(register_t);
414: }
415: }
416: while (argsize) {
1.27 mickey 417: if (c)
418: putchar(c);
1.1 deraadt 419: if (decimal)
1.27 mickey 420: (void)printf("%ld", (long)*ap);
1.1 deraadt 421: else
1.27 mickey 422: (void)printf("%#lx", (long)*ap);
1.1 deraadt 423: c = ',';
424: ap++;
425: argsize -= sizeof(register_t);
426: }
427: }
1.27 mickey 428: (void)printf(")\n");
1.1 deraadt 429: }
430:
1.12 espie 431: static void
1.17 deraadt 432: ktrsysret(struct ktr_sysret *ktr)
1.1 deraadt 433: {
1.12 espie 434: int ret = ktr->ktr_retval;
435: int error = ktr->ktr_error;
436: int code = ktr->ktr_code;
1.1 deraadt 437:
438: if (code >= current->nsysnames || code < 0)
439: (void)printf("[%d] ", code);
440: else
441: (void)printf("%s ", current->sysnames[code]);
442:
443: if (error == 0) {
444: if (fancy) {
445: (void)printf("%d", ret);
446: if (ret < 0 || ret > 9)
447: (void)printf("/%#x", ret);
448: } else {
449: if (decimal)
450: (void)printf("%d", ret);
451: else
452: (void)printf("%#x", ret);
453: }
454: } else if (error == ERESTART)
455: (void)printf("RESTART");
456: else if (error == EJUSTRETURN)
457: (void)printf("JUSTRETURN");
458: else {
459: (void)printf("-1 errno %d", ktr->ktr_error);
460: if (fancy)
461: (void)printf(" %s", strerror(ktr->ktr_error));
462: }
463: (void)putchar('\n');
464: }
465:
1.12 espie 466: static void
1.37 tedu 467: ktrnamei(const char *cp, size_t len)
1.1 deraadt 468: {
1.37 tedu 469: (void)printf("\"%.*s\"\n", (int)len, cp);
1.1 deraadt 470: }
471:
1.12 espie 472: static void
1.37 tedu 473: ktremul(char *cp, size_t len)
1.1 deraadt 474: {
475: char name[1024];
476:
477: if (len >= sizeof(name))
478: errx(1, "Emulation name too long");
479:
480: strncpy(name, cp, len);
481: name[len] = '\0';
482: (void)printf("\"%s\"\n", name);
483:
484: setemul(name);
485: }
486:
1.12 espie 487: static void
1.37 tedu 488: ktrgenio(struct ktr_genio *ktr, size_t len)
1.1 deraadt 489: {
1.37 tedu 490: unsigned char *dp = (unsigned char *)ktr + sizeof(struct ktr_genio);
491: int i, j;
492: size_t datalen = len - sizeof(struct ktr_genio);
1.12 espie 493: static int screenwidth = 0;
1.31 tedu 494: int col = 0, width, bpl;
1.32 tedu 495: unsigned char visbuf[5], *cp, c;
1.1 deraadt 496:
497: if (screenwidth == 0) {
498: struct winsize ws;
499:
500: if (fancy && ioctl(fileno(stderr), TIOCGWINSZ, &ws) != -1 &&
501: ws.ws_col > 8)
502: screenwidth = ws.ws_col;
503: else
504: screenwidth = 80;
505: }
1.37 tedu 506: printf("fd %d %s %zu bytes\n", ktr->ktr_fd,
1.1 deraadt 507: ktr->ktr_rw == UIO_READ ? "read" : "wrote", datalen);
508: if (maxdata && datalen > maxdata)
509: datalen = maxdata;
1.31 tedu 510: if (iohex && !datalen)
511: return;
512: if (iohex == 1) {
513: putchar('\t');
514: col = 8;
515: for (i = 0; i < datalen; i++) {
1.35 tedu 516: printf("%02x", dp[i]);
1.31 tedu 517: col += 3;
518: if (i < datalen - 1) {
519: if (col + 3 > screenwidth) {
520: printf("\n\t");
521: col = 8;
522: } else
523: putchar(' ');
524: }
525: }
526: putchar('\n');
527: return;
528: }
529: if (iohex == 2) {
530: bpl = (screenwidth - 13)/4;
531: if (bpl <= 0)
532: bpl = 1;
533: for (i = 0; i < datalen; i += bpl) {
534: printf(" %04x: ", i);
535: for (j = 0; j < bpl; j++) {
536: if (i+j >= datalen)
537: printf(" ");
538: else
1.35 tedu 539: printf("%02x ", dp[i+j]);
1.31 tedu 540: }
541: putchar(' ');
542: for (j = 0; j < bpl; j++) {
543: if (i+j >= datalen)
544: break;
545: c = dp[i+j];
546: if (!isprint(c))
547: c = '.';
548: putchar(c);
549: }
550: putchar('\n');
551: }
552: return;
553: }
1.1 deraadt 554: (void)printf(" \"");
555: col = 8;
556: for (; datalen > 0; datalen--, dp++) {
1.31 tedu 557: (void)vis(visbuf, *dp, VIS_CSTYLE, *(dp+1));
1.1 deraadt 558: cp = visbuf;
1.17 deraadt 559:
1.1 deraadt 560: /*
561: * Keep track of printables and
562: * space chars (like fold(1)).
563: */
564: if (col == 0) {
565: (void)putchar('\t');
566: col = 8;
567: }
1.17 deraadt 568: switch (*cp) {
1.1 deraadt 569: case '\n':
570: col = 0;
571: (void)putchar('\n');
572: continue;
573: case '\t':
574: width = 8 - (col&07);
575: break;
576: default:
577: width = strlen(cp);
578: }
579: if (col + width > (screenwidth-2)) {
580: (void)printf("\\\n\t");
581: col = 8;
582: }
583: col += width;
584: do {
585: (void)putchar(*cp++);
586: } while (*cp);
587: }
588: if (col == 0)
589: (void)printf(" ");
590: (void)printf("\"\n");
591: }
592:
1.12 espie 593: static void
1.17 deraadt 594: ktrpsig(struct ktr_psig *psig)
1.1 deraadt 595: {
596: (void)printf("SIG%s ", sys_signame[psig->signo]);
597: if (psig->action == SIG_DFL)
1.14 deraadt 598: (void)printf("SIG_DFL code %d", psig->code);
1.1 deraadt 599: else
1.14 deraadt 600: (void)printf("caught handler=0x%lx mask=0x%x",
601: (u_long)psig->action, psig->mask);
602: switch (psig->signo) {
603: case SIGSEGV:
604: case SIGILL:
605: case SIGBUS:
606: case SIGFPE:
607: printf(" addr=%p trapno=%d", psig->si.si_addr,
608: psig->si.si_trapno);
609: break;
610: default:
611: break;
612: }
613: printf("\n");
1.1 deraadt 614: }
615:
1.12 espie 616: static void
1.17 deraadt 617: ktrcsw(struct ktr_csw *cs)
1.1 deraadt 618: {
619: (void)printf("%s %s\n", cs->out ? "stop" : "resume",
620: cs->user ? "user" : "kernel");
621: }
622:
1.12 espie 623: static void
1.17 deraadt 624: usage(void)
1.1 deraadt 625: {
626:
1.19 mickey 627: extern char *__progname;
628: fprintf(stderr, "usage: %s "
1.40 sobrado 629: "[-dlnRTXx] [-e emulation] [-f file] [-m maxdata] [-p pid]\n"
630: "%*s[-t [ceinsw]]\n",
631: __progname, sizeof("usage: ") + strlen(__progname), "");
1.1 deraadt 632: exit(1);
633: }
634:
1.12 espie 635: static void
1.17 deraadt 636: setemul(const char *name)
1.1 deraadt 637: {
638: int i;
1.17 deraadt 639:
1.1 deraadt 640: for (i = 0; emulations[i].name != NULL; i++)
641: if (strcmp(emulations[i].name, name) == 0) {
642: current = &emulations[i];
643: return;
644: }
645: warnx("Emulation `%s' unknown", name);
646: }