loadbsd.c revision 1.18 1 /* $NetBSD: loadbsd.c,v 1.18 1996/01/28 20:01:10 chopps Exp $ */
2
3 /*
4 * Copyright (c) 1994 Michael L. Hitch
5 * 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.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by Michael L. Hitch.
18 * 4. The name of the author may not be used to endorse or promote products
19 * derived from this software without specific prior written permission
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32
33 #include <sys/types.h>
34 #include <a.out.h>
35 #include <stdio.h>
36 #include <unistd.h>
37 #include <errno.h>
38 #include <stdarg.h>
39 #include <signal.h>
40 #ifdef __NetBSD__
41 #include <err.h>
42 #endif
43 #include <exec/types.h>
44 #include <exec/execbase.h>
45 #include <exec/memory.h>
46 #include <exec/resident.h>
47 #include <graphics/gfxbase.h>
48 #include <libraries/configregs.h>
49 #include <libraries/configvars.h>
50 #include <libraries/expansion.h>
51 #include <libraries/expansionbase.h>
52
53 #include <inline/exec.h>
54 #include <inline/expansion.h>
55 #include <inline/graphics.h>
56
57 /* Get definitions for boothowto */
58 #include "reboot.h"
59
60 #undef __LDPGSZ
61 #define __LDPGSZ 8192
62
63 #ifndef __NetBSD__
64 #ifndef __P
65 #ifdef __STDC__
66 #define __P(x) x
67 #else
68 #define __P(x)
69 #endif
70 #endif
71 void err __P((int, const char *, ...));
72 void errx __P((int, const char *, ...));
73 void warn __P((const char *, ...));
74 void warnx __P((const char *, ...));
75 #endif
76
77 /*
78 * Version history:
79 * 1.x Kernel parameter passing version check.
80 * 2.0 Added symbol table end address and symbol table support.
81 * 2.1 03/23/94 - Round up end of fastram segment.
82 * Check fastram segment size for minimum of 2M.
83 * Use largest segment of highest priority if -p option.
84 * Print out fastram size in KB if not a multiple of MB.
85 * 2.2 03/24/94 - Zero out all unused registers.
86 * Started version history comment.
87 * 2.3 04/26/94 - Added -D option to enter debugger on boot.
88 * 2.4 04/30/94 - Cpuid includes base machine type.
89 * Also check if CPU is capable of running NetBSD.
90 * 2.5 05/17/94 - Add check for "A3000 bonus".
91 * 2.6 06/05/94 - Added -c option to override machine type.
92 * 2.7 06/15/94 - Pass E clock frequency.
93 * 2.8 06/22/94 - Fix supervisor stack usage.
94 * 2.9 06/26/94 - Use PAL flag for E clock freq on pre 2.0 WB
95 * Added AGA enable parameter
96 * 2.10 12/22/94 - Use FindResident() & OpenResource() for machine
97 * type detection.
98 * Add -n flag & option for non-contiguous memory.
99 * 01/28/95 - Corrected -n on usage & help messages.
100 * 2.11 03/12/95 - Check kernel size against chip memory size.
101 * 2.12 11/11/95 - Add -I option to inhibit synchronous transfer
102 * 11/12/95 - New kernel parameter version - to support passing
103 * a kernel parameter data structure and support moving kernel
104 * image to fastmem rather than chipmem.
105 */
106 static const char _version[] = "$VER: LoadBSD 2.12 (12.11.95)";
107
108 /*
109 * Kernel parameter passing version
110 * 1: first version of loadbsd
111 * 2: needs esym location passed in a4
112 * 3: allow kernel image in fastmem rather than chipmem, and
113 * passing kernel parameters in a data structure
114 */
115 #define KERNEL_PARAMETER_VERSION 3
116
117 #define MAXMEMSEG 16
118 struct boot_memlist {
119 u_int m_nseg; /* num_mem; */
120 struct boot_memseg {
121 u_int ms_start;
122 u_int ms_size;
123 u_short ms_attrib;
124 short ms_pri;
125 } m_seg[MAXMEMSEG];
126 };
127 struct boot_memlist memlist;
128 struct boot_memlist *kmemlist;
129
130
131 void get_mem_config __P((void **, u_long *, u_long *));
132 void get_cpuid __P((void));
133 void get_eclock __P((void));
134 void get_AGA __P((void));
135 void usage __P((void));
136 void verbose_usage __P((void));
137 void Version __P((void));
138
139 extern struct ExecBase *SysBase;
140 extern char *optarg;
141 extern int optind;
142
143 int k_flag;
144 int p_flag;
145 int t_flag;
146 int reqmemsz;
147 int S_flag;
148 u_long I_flag;
149 u_long cpuid;
150 long eclock_freq;
151 long amiga_flags;
152 char *program_name;
153 char *kname;
154 struct ExpansionBase *ExpansionBase;
155 struct GfxBase *GfxBase;
156
157
158 int
159 main(argc, argv)
160 int argc;
161 char **argv;
162 {
163 struct exec e;
164 struct ConfigDev *cd, *kcd;
165 u_long fmemsz, cmemsz;
166 int fd, boothowto, ksize, textsz, stringsz, ncd, i, mem_ix, ch;
167 u_short *kvers;
168 int *nkcd;
169 u_char *kp;
170 void *fmem;
171 char *esym;
172
173 program_name = argv[0];
174 boothowto = RB_SINGLE;
175
176 if (argc < 2)
177 usage();
178 if ((GfxBase = (void *)OpenLibrary(GRAPHICSNAME, 0)) == NULL)
179 err(20, "can't open graphics library");
180 if ((ExpansionBase=(void *)OpenLibrary(EXPANSIONNAME, 0)) == NULL)
181 err(20, "can't open expansion library");
182
183 while ((ch = getopt(argc, argv, "aAbc:DhI:km:n:ptSV")) != EOF) {
184 switch (ch) {
185 case 'k':
186 k_flag = 1;
187 break;
188 case 'a':
189 boothowto &= ~(RB_SINGLE);
190 boothowto |= RB_AUTOBOOT;
191 break;
192 case 'b':
193 boothowto |= RB_ASKNAME;
194 break;
195 case 'p':
196 p_flag = 1;
197 break;
198 case 't':
199 t_flag = 1;
200 break;
201 case 'm':
202 reqmemsz = atoi(optarg) * 1024;
203 break;
204 case 'V':
205 fprintf(stderr,"%s\n",_version + 6);
206 break;
207 case 'S':
208 S_flag = 1;
209 break;
210 case 'D':
211 boothowto |= RB_KDB;
212 break;
213 case 'c':
214 cpuid = atoi(optarg) << 16;
215 break;
216 case 'A':
217 amiga_flags |= 1;
218 break;
219 case 'n':
220 i = atoi(optarg);
221 if (i >= 0 && i <= 3)
222 amiga_flags |= i << 1;
223 else
224 err(20, "-n option must be 0, 1, 2, or 3");
225 break;
226 case 'I':
227 I_flag = strtoul(optarg, NULL, 16);
228 break;
229 case 'h':
230 verbose_usage();
231 default:
232 usage();
233 }
234 }
235 argc -= optind;
236 argv += optind;
237
238 if (argc != 1)
239 usage();
240 kname = argv[0];
241
242 if ((fd = open(kname, 0)) < 0)
243 err(20, "open");
244 if (read(fd, &e, sizeof(e)) != sizeof(e))
245 err(20, "reading exec");
246 if (e.a_magic != NMAGIC)
247 err(20, "unknown binary");
248
249 for (cd = 0, ncd = 0; cd = FindConfigDev(cd, -1, -1); ncd++)
250 ;
251 get_mem_config(&fmem, &fmemsz, &cmemsz);
252 get_cpuid();
253 get_eclock();
254 get_AGA();
255
256 textsz = (e.a_text + __LDPGSZ - 1) & (-__LDPGSZ);
257 esym = NULL;
258 ksize = textsz + e.a_data + e.a_bss + ncd * sizeof(*cd)
259 + 4 + memlist.m_nseg * sizeof(struct boot_memseg) + 4;
260
261 /*
262 * get symbol table size & string size
263 * (should check kernel version to see if it will handle it)
264 */
265 if (S_flag && e.a_syms) {
266 if (lseek(fd, e.a_text + e.a_data + e.a_syms, SEEK_CUR) <= 0
267 || read(fd, &stringsz, 4) != 4
268 || lseek(fd, sizeof(e), SEEK_SET) < 0)
269 err(20, "lseek for symbols");
270 ksize += e.a_syms + 4 + stringsz;
271 }
272
273 if (ksize >= cmemsz) {
274 printf("Kernel size %d exceeds Chip Memory of %d\n",
275 ksize, cmemsz);
276 err(20, "Insufficient Chip Memory for kernel");
277 }
278 kp = (u_char *)malloc(ksize);
279 if (t_flag) {
280 for (i = 0; i < memlist.m_nseg; ++i) {
281 printf("mem segment %d: start=%08lx size=%08lx"
282 " attribute=%04lx pri=%d\n",
283 i + 1, memlist.m_seg[i].ms_start,
284 memlist.m_seg[i].ms_size,
285 memlist.m_seg[i].ms_attrib,
286 memlist.m_seg[i].ms_pri);
287 }
288 printf("kernel size: %d\n", ksize);
289 }
290 if (kp == NULL)
291 err(20, "failed malloc %d\n", ksize);
292
293 if (read(fd, kp, e.a_text) != e.a_text
294 || read(fd, kp + textsz, e.a_data) != e.a_data)
295 err(20, "unable to read kernel image\n");
296
297 if (k_flag) {
298 fmem += 4 * 1024 * 1024;
299 fmemsz -= 4 * 1024 * 1024;
300 }
301
302 if (reqmemsz && reqmemsz <= fmemsz)
303 fmemsz = reqmemsz;
304 if (boothowto & RB_AUTOBOOT)
305 printf("Autobooting...");
306 if (boothowto & RB_ASKNAME)
307 printf("Askboot...");
308
309 printf("Using %d%c FASTMEM at 0x%x, %dM CHIPMEM\n",
310 (fmemsz & 0xfffff) ? fmemsz >> 10 : fmemsz >> 20,
311 (fmemsz & 0xfffff) ? 'K' : 'M', fmem, cmemsz >> 20);
312 kvers = (u_short *)(kp + e.a_entry - 2);
313 if (*kvers > KERNEL_PARAMETER_VERSION && *kvers != 0x4e73)
314 err(20, "newer loadbsd required: %d\n", *kvers);
315 if (*kvers > 2) {
316 printf("****************************************************\n");
317 printf("*** Notice: this kernel has features which require\n");
318 printf("*** a newer version of loadbsd. To allow the use of\n");
319 printf("*** any newer features or capabilities, you should\n");
320 printf("*** update your copy of loadbsd\n");
321 printf("****************************************************\n");
322 sleep(3); /* even more time to see that message */
323 }
324 if ((cpuid & AFB_68020) == 0)
325 err(20, "cpu not supported");
326 /*
327 * give them a chance to read the information...
328 */
329 sleep(2);
330
331 bzero(kp + textsz + e.a_data, e.a_bss);
332 /*
333 * If symbols wanted (and kernel can handle them),
334 * load symbol table & strings and set esym to end.
335 */
336 nkcd = (int *)(kp + textsz + e.a_data + e.a_bss);
337 if (*kvers != 0x4e73 && *kvers > 1 && S_flag && e.a_syms) {
338 *nkcd++ = e.a_syms;
339 read(fd, (char *)nkcd, e.a_syms);
340 nkcd = (int *)((char *)nkcd + e.a_syms);
341 read(fd, (char *)nkcd, stringsz);
342 nkcd = (int*)((char *)nkcd + stringsz);
343 esym = (char *)(textsz + e.a_data + e.a_bss
344 + e.a_syms + 4 + stringsz);
345 }
346 *nkcd = ncd;
347
348 kcd = (struct ConfigDev *)(nkcd + 1);
349 while(cd = FindConfigDev(cd, -1, -1))
350 *kcd++ = *cd;
351
352 kmemlist = (struct boot_memlist *)kcd;
353 kmemlist->m_nseg = memlist.m_nseg;
354 for (mem_ix = 0; mem_ix < memlist.m_nseg; mem_ix++)
355 kmemlist->m_seg[mem_ix] = memlist.m_seg[mem_ix];
356 /*
357 * if test option set, done
358 */
359 if (t_flag)
360 exit(0);
361
362 /*
363 * XXX AGA startup - may need more
364 */
365 LoadView(NULL); /* Don't do this if AGA active? */
366 startit(kp, ksize, e.a_entry, fmem, fmemsz, cmemsz, boothowto, esym,
367 cpuid, eclock_freq, amiga_flags, I_flag);
368 /*NOTREACHED*/
369 }
370
371 void
372 get_mem_config(fmem, fmemsz, cmemsz)
373 void **fmem;
374 u_long *fmemsz, *cmemsz;
375 {
376 struct MemHeader *mh, *nmh;
377 u_int segsz, seg, eseg, nmem;
378 char mempri;
379
380 nmem = 0;
381 mempri = -128;
382 *fmemsz = 0;
383 *cmemsz = 0;
384
385 /*
386 * walk thru the exec memory list
387 */
388 Forbid();
389 for (mh = (void *) SysBase->MemList.lh_Head;
390 nmh = (void *) mh->mh_Node.ln_Succ; mh = nmh, nmem++) {
391 memlist.m_seg[nmem].ms_attrib = mh->mh_Attributes;
392 memlist.m_seg[nmem].ms_pri = mh->mh_Node.ln_Pri;
393 seg = (u_int)mh->mh_Lower;
394 eseg = (u_int)mh->mh_Upper;
395 segsz = eseg - seg;
396 memlist.m_seg[nmem].ms_size = segsz;
397 memlist.m_seg[nmem].ms_start = seg;
398
399 if (mh->mh_Attributes & MEMF_CHIP) {
400 /*
401 * there should hardly be more than one entry for
402 * chip mem, but handle it the same nevertheless
403 * cmem always starts at 0, so include vector area
404 */
405 memlist.m_seg[nmem].ms_start = seg = 0;
406 /*
407 * round to multiple of 512K
408 */
409 segsz = (segsz + 512 * 1024 - 1) & -(512 * 1024);
410 memlist.m_seg[nmem].ms_size = segsz;
411 if (segsz > *cmemsz)
412 *cmemsz = segsz;
413 continue;
414 }
415 /*
416 * some heuristics..
417 */
418 seg &= -__LDPGSZ;
419 eseg = (eseg + __LDPGSZ - 1) & -__LDPGSZ;
420
421 /*
422 * get the mem back stolen by incore kickstart on
423 * A3000 with V36 bootrom.
424 */
425 if (eseg == 0x07f80000)
426 eseg = 0x08000000;
427
428 /*
429 * or by zkick on a A2000.
430 */
431 if (seg == 0x280000 &&
432 strcmp(mh->mh_Node.ln_Name, "zkick memory") == 0)
433 seg = 0x200000;
434
435 segsz = eseg - seg;
436 memlist.m_seg[nmem].ms_start = seg;
437 memlist.m_seg[nmem].ms_size = segsz;
438 /*
439 * If this segment is smaller than 2M,
440 * don't use it to load the kernel
441 */
442 if (segsz < 2 * 1024 * 1024)
443 continue;
444 /*
445 * if p_flag is set, select memory by priority
446 * instead of size
447 */
448 if ((!p_flag && segsz > *fmemsz) || (p_flag &&
449 mempri <= mh->mh_Node.ln_Pri && segsz > *fmemsz)) {
450 *fmemsz = segsz;
451 *fmem = (void *)seg;
452 mempri = mh->mh_Node.ln_Pri;
453 }
454 }
455 memlist.m_nseg = nmem;
456 Permit();
457 }
458
459 /*
460 * Try to determine the machine ID by searching the resident module list
461 * for modules only present on specific machines. (Thanks, Bill!)
462 */
463 void
464 get_cpuid()
465 {
466 u_long *rl;
467 struct Resident *rm;
468 struct Node *rn; /* Resource node entry */
469
470 cpuid |= SysBase->AttnFlags; /* get FPU and CPU flags */
471 if (cpuid & 0xffff0000) {
472 switch (cpuid >> 16) {
473 case 500:
474 case 600:
475 case 1000:
476 case 1200:
477 case 2000:
478 case 3000:
479 case 4000:
480 return;
481 default:
482 printf("machine Amiga %d is not recognized\n",
483 cpuid >> 16);
484 exit(1);
485 }
486 }
487 if (FindResident("A4000 Bonus") || FindResident("A4000 bonus")
488 || FindResident("A1000 Bonus"))
489 cpuid |= 4000 << 16;
490 else if (FindResident("A3000 Bonus") || FindResident("A3000 bonus"))
491 cpuid |= 3000 << 16;
492 else if (OpenResource("card.resource")) {
493 /* Test for AGA? */
494 cpuid |= 1200 << 16;
495 }
496 /*
497 * Nothing found, it's probably an A2000 or A500
498 */
499 if ((cpuid >> 16) == 0)
500 cpuid |= 2000 << 16;
501 }
502
503 void
504 get_eclock()
505 {
506 /* Fix for 1.3 startups? */
507 if (SysBase->LibNode.lib_Version > 36)
508 eclock_freq = SysBase->ex_EClockFrequency;
509 else
510 eclock_freq = (GfxBase->DisplayFlags & PAL) ?
511 709379 : 715909;
512 }
513
514 void
515 get_AGA()
516 {
517 /*
518 * Determine if an AGA mode is active
519 */
520 }
521
522
523 asm("
524 .set ABSEXECBASE,4
525
526 .text
527 .globl _startit
528
529 _startit:
530 movel sp,a3
531 movel 4:w,a6
532 lea pc@(start_super-.+2),a5
533 jmp a6@(-0x1e) | supervisor-call
534
535 start_super:
536 movew #0x2700,sr
537
538 | the BSD kernel wants values into the following registers:
539 | a0: fastmem-start
540 | d0: fastmem-size
541 | d1: chipmem-size
542 | d3: Amiga specific flags
543 | d4: E clock frequency
544 | d5: AttnFlags (cpuid)
545 | d7: boothowto
546 | a4: esym location
547 | a2: Inhibit sync flags
548 | All other registers zeroed for possible future requirements.
549
550 lea pc@(_startit-.+2),sp | make sure we have a good stack ***
551 movel a3@(4),a1 | loaded kernel
552 movel a3@(8),d2 | length of loaded kernel
553 | movel a3@(12),sp | entry point in stack pointer
554 movel a3@(12),sp@- | push entry point ***
555 movel a3@(16),a0 | fastmem-start
556 movel a3@(20),d0 | fastmem-size
557 movel a3@(24),d1 | chipmem-size
558 movel a3@(28),d7 | boothowto
559 movel a3@(32),a4 | esym
560 movel a3@(36),d5 | cpuid
561 movel a3@(40),d4 | E clock frequency
562 movel a3@(44),d3 | Amiga flags
563 movel a3@(48),a2 | Inhibit sync flags
564 subl a5,a5 | target, load to 0
565
566 btst #3,(ABSEXECBASE)@(0x129) | AFB_68040,SysBase->AttnFlags
567 beq not040
568
569 | Turn off 68040 MMU
570
571 .word 0x4e7b,0xd003 | movec a5,tc
572 .word 0x4e7b,0xd806 | movec a5,urp
573 .word 0x4e7b,0xd807 | movec a5,srp
574 .word 0x4e7b,0xd004 | movec a5,itt0
575 .word 0x4e7b,0xd005 | movec a5,itt1
576 .word 0x4e7b,0xd006 | movec a5,dtt0
577 .word 0x4e7b,0xd007 | movec a5,dtt1
578 bra nott
579
580 not040:
581 lea pc@(zero-.+2),a3
582 pmove a3@,tc | Turn off MMU
583 lea pc@(nullrp-.+2),a3
584 pmove a3@,crp | Turn off MMU some more
585 pmove a3@,srp | Really, really, turn off MMU
586
587 | Turn off 68030 TT registers
588
589 btst #2,(ABSEXECBASE)@(0x129) | AFB_68030,SysBase->AttnFlags
590 beq nott | Skip TT registers if not 68030
591 lea pc@(zero-.+2),a3
592 .word 0xf013,0x0800 | pmove a3@,tt0 (gas only knows about 68851 ops..)
593 .word 0xf013,0x0c00 | pmove a3@,tt1 (gas only knows about 68851 ops..)
594
595 nott:
596
597 movew #(1<<9),0xdff096 | disable DMA
598
599 L0:
600 moveb a1@+,a5@+
601 subl #1,d2
602 bcc L0
603
604
605 moveq #0,d2 | zero out unused registers
606 moveq #0,d6 | (might make future compatibility
607 movel d6,a1 | would have known contents)
608 movel d6,a3
609 movel d6,a5
610 movel d6,a6
611 | jmp sp@ | jump to kernel entry point
612 rts | enter kernel at address on stack ***
613
614
615 | A do-nothing MMU root pointer (includes the following long as well)
616
617 nullrp: .long 0x7fff0001
618 zero: .long 0
619
620
621 ");
622
623 void
624 usage()
625 {
626 fprintf(stderr, "usage: %s [-abhkptADSV] [-c machine] [-m mem] [-n mode] [-I sync-inhibit] kernel\n",
627 program_name);
628 exit(1);
629 }
630
631
632 void
633 verbose_usage()
634 {
635 fprintf(stderr, "
636 NAME
637 \t%s - loads NetBSD from amiga dos.
638 SYNOPSIS
639 \t%s [-abhkptDSV] [-c machine] [-m mem] [-n flags] kernel
640 OPTIONS
641 \t-a Boot up to multiuser mode.
642 \t-A Use AGA display mode, if available.
643 \t-b Ask for which root device.
644 \t Its possible to have multiple roots and choose between them.
645 \t-c Set machine type. [e.g 3000]
646 \t-D Enter debugger
647 \t-h This help message.
648 \t-I Inhibit sync negotiation. Option value is bit-encoded targets.
649 \t-k Reserve the first 4M of fast mem [Some one else
650 \t is going to have to answer what that it is used for].
651 \t-m Tweak amount of available memory, for finding minimum amount
652 \t of memory required to run. Sets fastmem size to specified
653 \t size in Kbytes.
654 \t-n Enable multiple non-contiguous memory: value = 0 (disabled),
655 \t 1 (two segments), 2 (all avail segments), 3 (same as 2?).
656 \t-p Use highest priority fastmem segement instead of the largest
657 \t segment. The higher priority segment is usually faster
658 \t (i.e. 32 bit memory), but some people have smaller amounts
659 \t of 32 bit memory.
660 \t-S Include kernel symbol table.
661 \t-t This is a *test* option. It prints out the memory
662 \t list information being passed to the kernel and also
663 \t exits without actually starting NetBSD.
664 \t-V Version of loadbsd program.
665 HISTORY
666 \tThis version supports Kernel version 720 +\n",
667 program_name, program_name);
668 exit(1);
669 }
670
671
672 void
673 _Vdomessage(doexit, eval, doerrno, fmt, args)
674 int doexit, doerrno, eval;
675 const char *fmt;
676 va_list args;
677 {
678 fprintf(stderr, "%s: ", program_name);
679 if (fmt) {
680 vfprintf(stderr, fmt, args);
681 fprintf(stderr, ": ");
682 }
683 if (doerrno && errno < sys_nerr) {
684 fprintf(stderr, "%s", strerror(errno));
685 if (errno == EINTR || errno == 0) {
686 int sigs;
687 sigpending((sigset_t *)&sigs);
688 printf("%x\n", sigs);
689 }
690 }
691 fprintf(stderr, "\n");
692 if (doexit)
693 exit(eval);
694 }
695
696 void
697 err(int eval, const char *fmt, ...)
698 {
699 va_list ap;
700 va_start(ap, fmt);
701 _Vdomessage(1, eval, 1, fmt, ap);
702 /*NOTREACHED*/
703 }
704
705 void
706 errx(int eval, const char *fmt, ...)
707 {
708 va_list ap;
709 va_start(ap, fmt);
710 _Vdomessage(1, eval, 0, fmt, ap);
711 /*NOTREACHED*/
712 }
713
714 void
715 warn(const char *fmt, ...)
716 {
717 va_list ap;
718 va_start(ap, fmt);
719 _Vdomessage(0, 0, 1, fmt, ap);
720 va_end(ap);
721 }
722
723 void
724 warnx(const char *fmt, ...)
725 {
726 va_list ap;
727 va_start(ap, fmt);
728 _Vdomessage(0, 0, 0, fmt, ap);
729 va_end(ap);
730 }
731