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