loadbsd.c revision 1.17 1 /* $NetBSD: loadbsd.c,v 1.17 1995/11/30 00:57:29 jtc 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("A1000 Bonus"))
488 cpuid |= 4000 << 16;
489 else if (FindResident("A3000 Bonus") || FindResident("A3000 bonus"))
490 cpuid |= 3000 << 16;
491 else if (OpenResource("card.resource")) {
492 /* Test for AGA? */
493 cpuid |= 1200 << 16;
494 }
495 /*
496 * Nothing found, it's probably an A2000 or A500
497 */
498 if ((cpuid >> 16) == 0)
499 cpuid |= 2000 << 16;
500 }
501
502 void
503 get_eclock()
504 {
505 /* Fix for 1.3 startups? */
506 if (SysBase->LibNode.lib_Version > 36)
507 eclock_freq = SysBase->ex_EClockFrequency;
508 else
509 eclock_freq = (GfxBase->DisplayFlags & PAL) ?
510 709379 : 715909;
511 }
512
513 void
514 get_AGA()
515 {
516 /*
517 * Determine if an AGA mode is active
518 */
519 }
520
521
522 asm("
523 .set ABSEXECBASE,4
524
525 .text
526 .globl _startit
527
528 _startit:
529 movel sp,a3
530 movel 4:w,a6
531 lea pc@(start_super-.+2),a5
532 jmp a6@(-0x1e) | supervisor-call
533
534 start_super:
535 movew #0x2700,sr
536
537 | the BSD kernel wants values into the following registers:
538 | a0: fastmem-start
539 | d0: fastmem-size
540 | d1: chipmem-size
541 | d3: Amiga specific flags
542 | d4: E clock frequency
543 | d5: AttnFlags (cpuid)
544 | d7: boothowto
545 | a4: esym location
546 | a2: Inhibit sync flags
547 | All other registers zeroed for possible future requirements.
548
549 lea pc@(_startit-.+2),sp | make sure we have a good stack ***
550 movel a3@(4),a1 | loaded kernel
551 movel a3@(8),d2 | length of loaded kernel
552 | movel a3@(12),sp | entry point in stack pointer
553 movel a3@(12),sp@- | push entry point ***
554 movel a3@(16),a0 | fastmem-start
555 movel a3@(20),d0 | fastmem-size
556 movel a3@(24),d1 | chipmem-size
557 movel a3@(28),d7 | boothowto
558 movel a3@(32),a4 | esym
559 movel a3@(36),d5 | cpuid
560 movel a3@(40),d4 | E clock frequency
561 movel a3@(44),d3 | Amiga flags
562 movel a3@(48),a2 | Inhibit sync flags
563 subl a5,a5 | target, load to 0
564
565 btst #3,(ABSEXECBASE)@(0x129) | AFB_68040,SysBase->AttnFlags
566 beq not040
567
568 | Turn off 68040 MMU
569
570 .word 0x4e7b,0xd003 | movec a5,tc
571 .word 0x4e7b,0xd806 | movec a5,urp
572 .word 0x4e7b,0xd807 | movec a5,srp
573 .word 0x4e7b,0xd004 | movec a5,itt0
574 .word 0x4e7b,0xd005 | movec a5,itt1
575 .word 0x4e7b,0xd006 | movec a5,dtt0
576 .word 0x4e7b,0xd007 | movec a5,dtt1
577 bra nott
578
579 not040:
580 lea pc@(zero-.+2),a3
581 pmove a3@,tc | Turn off MMU
582 lea pc@(nullrp-.+2),a3
583 pmove a3@,crp | Turn off MMU some more
584 pmove a3@,srp | Really, really, turn off MMU
585
586 | Turn off 68030 TT registers
587
588 btst #2,(ABSEXECBASE)@(0x129) | AFB_68030,SysBase->AttnFlags
589 beq nott | Skip TT registers if not 68030
590 lea pc@(zero-.+2),a3
591 .word 0xf013,0x0800 | pmove a3@,tt0 (gas only knows about 68851 ops..)
592 .word 0xf013,0x0c00 | pmove a3@,tt1 (gas only knows about 68851 ops..)
593
594 nott:
595
596 movew #(1<<9),0xdff096 | disable DMA
597
598 L0:
599 moveb a1@+,a5@+
600 subl #1,d2
601 bcc L0
602
603
604 moveq #0,d2 | zero out unused registers
605 moveq #0,d6 | (might make future compatibility
606 movel d6,a1 | would have known contents)
607 movel d6,a3
608 movel d6,a5
609 movel d6,a6
610 | jmp sp@ | jump to kernel entry point
611 rts | enter kernel at address on stack ***
612
613
614 | A do-nothing MMU root pointer (includes the following long as well)
615
616 nullrp: .long 0x7fff0001
617 zero: .long 0
618
619
620 ");
621
622 void
623 usage()
624 {
625 fprintf(stderr, "usage: %s [-abhkptADSV] [-c machine] [-m mem] [-n mode] [-I sync-inhibit] kernel\n",
626 program_name);
627 exit(1);
628 }
629
630
631 void
632 verbose_usage()
633 {
634 fprintf(stderr, "
635 NAME
636 \t%s - loads NetBSD from amiga dos.
637 SYNOPSIS
638 \t%s [-abhkptDSV] [-c machine] [-m mem] [-n flags] kernel
639 OPTIONS
640 \t-a Boot up to multiuser mode.
641 \t-A Use AGA display mode, if available.
642 \t-b Ask for which root device.
643 \t Its possible to have multiple roots and choose between them.
644 \t-c Set machine type. [e.g 3000]
645 \t-D Enter debugger
646 \t-h This help message.
647 \t-I Inhibit sync negotiation. Option value is bit-encoded targets.
648 \t-k Reserve the first 4M of fast mem [Some one else
649 \t is going to have to answer what that it is used for].
650 \t-m Tweak amount of available memory, for finding minimum amount
651 \t of memory required to run. Sets fastmem size to specified
652 \t size in Kbytes.
653 \t-n Enable multiple non-contiguous memory: value = 0 (disabled),
654 \t 1 (two segments), 2 (all avail segments), 3 (same as 2?).
655 \t-p Use highest priority fastmem segement instead of the largest
656 \t segment. The higher priority segment is usually faster
657 \t (i.e. 32 bit memory), but some people have smaller amounts
658 \t of 32 bit memory.
659 \t-S Include kernel symbol table.
660 \t-t This is a *test* option. It prints out the memory
661 \t list information being passed to the kernel and also
662 \t exits without actually starting NetBSD.
663 \t-V Version of loadbsd program.
664 HISTORY
665 \tThis version supports Kernel version 720 +\n",
666 program_name, program_name);
667 exit(1);
668 }
669
670
671 void
672 _Vdomessage(doexit, eval, doerrno, fmt, args)
673 int doexit, doerrno, eval;
674 const char *fmt;
675 va_list args;
676 {
677 fprintf(stderr, "%s: ", program_name);
678 if (fmt) {
679 vfprintf(stderr, fmt, args);
680 fprintf(stderr, ": ");
681 }
682 if (doerrno && errno < sys_nerr) {
683 fprintf(stderr, "%s", strerror(errno));
684 if (errno == EINTR || errno == 0) {
685 int sigs;
686 sigpending((sigset_t *)&sigs);
687 printf("%x\n", sigs);
688 }
689 }
690 fprintf(stderr, "\n");
691 if (doexit)
692 exit(eval);
693 }
694
695 void
696 err(int eval, const char *fmt, ...)
697 {
698 va_list ap;
699 va_start(ap, fmt);
700 _Vdomessage(1, eval, 1, fmt, ap);
701 /*NOTREACHED*/
702 }
703
704 void
705 errx(int eval, const char *fmt, ...)
706 {
707 va_list ap;
708 va_start(ap, fmt);
709 _Vdomessage(1, eval, 0, fmt, ap);
710 /*NOTREACHED*/
711 }
712
713 void
714 warn(const char *fmt, ...)
715 {
716 va_list ap;
717 va_start(ap, fmt);
718 _Vdomessage(0, 0, 1, fmt, ap);
719 va_end(ap);
720 }
721
722 void
723 warnx(const char *fmt, ...)
724 {
725 va_list ap;
726 va_start(ap, fmt);
727 _Vdomessage(0, 0, 0, fmt, ap);
728 va_end(ap);
729 }
730