1/* $NetBSD$ */ 2 3/* 4 * tickadj - read, and possibly modify, the kernel `tick' and 5 * `tickadj' variables, as well as `dosynctodr'. Note that 6 * this operates on the running kernel only. I'd like to be 7 * able to read and write the binary as well, but haven't 8 * mastered this yet. 9 * 10 * HMS: The #includes here are different from those in xntpd/ntp_unixclock.c 11 * These seem "worse". 12 */ 13 14#ifdef HAVE_CONFIG_H 15# include <config.h> 16#endif 17 18#include "ntp_types.h" 19#include "l_stdlib.h" 20 21#include <stdio.h> 22#ifdef HAVE_UNISTD_H 23# include <unistd.h> 24#endif /* HAVE_UNISTD_H */ 25 26#ifdef HAVE___ADJTIMEX /* Linux */ 27 28#include <sys/timex.h> 29struct timex txc; 30 31#if 0 32int 33main( 34 int argc, 35 char *argv[] 36 ) 37{ 38 int c, i; 39 int quiet = 0; 40 int errflg = 0; 41 char *progname; 42 extern int ntp_optind; 43 extern char *ntp_optarg; 44 45 progname = argv[0]; 46 if (argc==2 && argv[1][0] != '-') { /* old Linux format, for compatability */ 47 if ((i = atoi(argv[1])) > 0) { 48 txc.time_tick = i; 49 txc.modes = ADJ_TIMETICK; 50 } else { 51 fprintf(stderr, "Silly value for tick: %s\n", argv[1]); 52 errflg++; 53 } 54 } else { 55 while ((c = ntp_getopt(argc, argv, "a:qt:")) != EOF) { 56 switch (c) { 57 case 'a': 58 if ((i=atoi(ntp_optarg)) > 0) { 59 txc.tickadj = i; 60 txc.modes |= ADJ_TICKADJ; 61 } else { 62 (void) fprintf(stderr, 63 "%s: unlikely value for tickadj: %s\n", 64 progname, ntp_optarg); 65 errflg++; 66 } 67 break; 68 69 case 'q': 70 quiet = 1; 71 break; 72 73 case 't': 74 if ((i=atoi(ntp_optarg)) > 0) { 75 txc.time_tick = i; 76 txc.modes |= ADJ_TIMETICK; 77 } else { 78 (void) fprintf(stderr, 79 "%s: unlikely value for tick: %s\n", 80 progname, ntp_optarg); 81 errflg++; 82 } 83 break; 84 85 default: 86 fprintf(stderr, 87 "Usage: %s [tick_value]\n-or- %s [ -q ] [ -t tick ] [ -a tickadj ]\n", 88 progname, progname); 89 errflg++; 90 break; 91 } 92 } 93 } 94 95 if (!errflg) { 96 if (__adjtimex(&txc) < 0) 97 perror("adjtimex"); 98 else if (!quiet) 99 printf("tick = %ld\ntick_adj = %d\n", 100 txc.time_tick, txc.tickadj); 101 } 102 103 exit(errflg ? 1 : 0); 104} 105#else 106int 107main( 108 int argc, 109 char *argv[] 110 ) 111{ 112 if (argc > 2) 113 { 114 fprintf(stderr, "Usage: %s [tick_value]\n", argv[0]); 115 exit(-1); 116 } 117 else if (argc == 2) 118 { 119#ifdef ADJ_TIMETICK 120 if ( (txc.time_tick = atoi(argv[1])) < 1 ) 121#else 122 if ( (txc.tick = atoi(argv[1])) < 1 ) 123#endif 124 { 125 fprintf(stderr, "Silly value for tick: %s\n", argv[1]); 126 exit(-1); 127 } 128#ifdef ADJ_TIMETICK 129 txc.modes = ADJ_TIMETICK; 130#else 131#ifdef MOD_OFFSET 132 txc.modes = ADJ_TICK; 133#else 134 txc.mode = ADJ_TICK; 135#endif 136#endif 137 } 138 else 139 { 140#ifdef ADJ_TIMETICK 141 txc.modes = 0; 142#else 143#ifdef MOD_OFFSET 144 txc.modes = 0; 145#else 146 txc.mode = 0; 147#endif 148#endif 149 } 150 151 if (__adjtimex(&txc) < 0) 152 { 153 perror("adjtimex"); 154 } 155 else 156 { 157#ifdef ADJ_TIMETICK 158 printf("tick = %ld\ntick_adj = %ld\n", txc.time_tick, txc.tickadj); 159#else 160 printf("tick = %ld\n", txc.tick); 161#endif 162 } 163 164 exit(0); 165} 166#endif 167 168#else /* not Linux... kmem tweaking: */ 169 170#ifdef HAVE_SYS_FILE_H 171# include <sys/file.h> 172#endif 173#include <sys/stat.h> 174 175#ifdef HAVE_SYS_PARAM_H 176# include <sys/param.h> 177#endif 178 179#ifdef NLIST_STRUCT 180# include <nlist.h> 181#else /* not NLIST_STRUCT */ /* was defined(SYS_AUX3) || defined(SYS_AUX2) */ 182# include <sys/resource.h> 183# include <sys/file.h> 184# include <a.out.h> 185# ifdef HAVE_SYS_VAR_H 186# include <sys/var.h> 187# endif 188#endif 189 190#include "ntp_stdlib.h" 191#include "ntp_io.h" 192 193#ifdef hz /* Was: RS6000 */ 194# undef hz 195#endif /* hz */ 196 197#ifdef HAVE_KVM_OPEN 198# include <kvm.h> 199#endif 200 201#ifdef SYS_VXWORKS 202/* vxWorks needs mode flag -casey*/ 203#define open(name, flags) open(name, flags, 0777) 204#endif 205 206#ifndef L_SET /* Was: defined(SYS_PTX) || defined(SYS_IX86OSF1) */ 207# define L_SET SEEK_SET 208#endif 209 210#ifndef HZ 211# define HZ DEFAULT_HZ 212#endif 213 214#define KMEM "/dev/kmem" 215#define STREQ(a, b) (*(a) == *(b) && strcmp((a), (b)) == 0) 216 217char *progname; 218volatile int debug; 219 220int dokmem = 1; 221int writetickadj = 0; 222int writeopttickadj = 0; 223int unsetdosync = 0; 224int writetick = 0; 225int quiet = 0; 226int setnoprintf = 0; 227 228const char *kmem = KMEM; 229const char *file = NULL; 230int fd = -1; 231 232static void getoffsets (off_t *, off_t *, off_t *, off_t *); 233static int openfile (const char *, int); 234static void writevar (int, off_t, int); 235static void readvar (int, off_t, int *); 236 237/* 238 * main - parse arguments and handle options 239 */ 240int 241main( 242 int argc, 243 char *argv[] 244 ) 245{ 246 int c; 247 int errflg = 0; 248 off_t tickadj_offset; 249 off_t tick_offset; 250 off_t dosync_offset; 251 off_t noprintf_offset; 252 int tickadj, ktickadj; /* HMS: Why isn't this u_long? */ 253 int tick, ktick; /* HMS: Why isn't this u_long? */ 254 int dosynctodr; 255 int noprintf; 256 int hz; 257 int hz_int, hz_hundredths; 258 int recommend_tickadj; 259 long tmp; 260 261 progname = argv[0]; 262 while ((c = ntp_getopt(argc, argv, "a:Adkpqst:")) != EOF) 263 { 264 switch (c) 265 { 266 case 'a': 267 writetickadj = atoi(ntp_optarg); 268 if (writetickadj <= 0) 269 { 270 (void) fprintf(stderr, 271 "%s: unlikely value for tickadj: %s\n", 272 progname, ntp_optarg); 273 errflg++; 274 } 275 276#if defined SCO5_CLOCK 277 if (writetickadj % HZ) 278 { 279 writetickadj = (writetickadj / HZ) * HZ; 280 (void) fprintf(stderr, 281 "tickadj truncated to: %d\n", writetickadj); 282 } 283#endif /* SCO5_CLOCK */ 284 285 break; 286 case 'A': 287 writeopttickadj = 1; 288 break; 289 case 'd': 290 ++debug; 291 break; 292 case 'k': 293 dokmem = 1; 294 break; 295 case 'p': 296 setnoprintf = 1; 297 break; 298 case 'q': 299 quiet = 1; 300 break; 301 case 's': 302 unsetdosync = 1; 303 break; 304 case 't': 305 writetick = atoi(ntp_optarg); 306 if (writetick <= 0) 307 { 308 (void) fprintf(stderr, 309 "%s: unlikely value for tick: %s\n", 310 progname, ntp_optarg); 311 errflg++; 312 } 313 break; 314 default: 315 errflg++; 316 break; 317 } 318 } 319 if (errflg || ntp_optind != argc) 320 { 321 (void) fprintf(stderr, 322 "usage: %s [-Adkpqs] [-a newadj] [-t newtick]\n", progname); 323 exit(2); 324 } 325 326 getoffsets(&tick_offset, &tickadj_offset, &dosync_offset, &noprintf_offset); 327 328 if (debug) 329 { 330 (void) printf("tick offset = %lu\n", (unsigned long)tick_offset); 331 (void) printf("tickadj offset = %lu\n", (unsigned long)tickadj_offset); 332 (void) printf("dosynctodr offset = %lu\n", (unsigned long)dosync_offset); 333 (void) printf("noprintf offset = %lu\n", (unsigned long)noprintf_offset); 334 } 335 336 if (writetick && (tick_offset == 0)) 337 { 338 (void) fprintf(stderr, 339 "No tick kernel variable\n"); 340 errflg++; 341 } 342 343 if (writeopttickadj && (tickadj_offset == 0)) 344 { 345 (void) fprintf(stderr, 346 "No tickadj kernel variable\n"); 347 errflg++; 348 } 349 350 if (unsetdosync && (dosync_offset == 0)) 351 { 352 (void) fprintf(stderr, 353 "No dosynctodr kernel variable\n"); 354 errflg++; 355 } 356 357 if (setnoprintf && (noprintf_offset == 0)) 358 { 359 (void) fprintf(stderr, 360 "No noprintf kernel variable\n"); 361 errflg++; 362 } 363 364 if (tick_offset != 0) 365 { 366 readvar(fd, tick_offset, &tick); 367#if defined(TICK_NANO) && defined(K_TICK_NAME) 368 if (!quiet) 369 (void) printf("KERNEL %s = %d nsec\n", K_TICK_NAME, tick); 370#endif /* TICK_NANO && K_TICK_NAME */ 371 372#ifdef TICK_NANO 373 tick /= 1000; 374#endif 375 } 376 else 377 { 378 tick = 0; 379 } 380 381 if (tickadj_offset != 0) 382 { 383 readvar(fd, tickadj_offset, &tickadj); 384 385#ifdef SCO5_CLOCK 386 /* scale from nsec/sec to usec/tick */ 387 tickadj /= (1000L * HZ); 388#endif /*SCO5_CLOCK */ 389 390#if defined(TICKADJ_NANO) && defined(K_TICKADJ_NAME) 391 if (!quiet) 392 (void) printf("KERNEL %s = %d nsec\n", K_TICKADJ_NAME, tickadj); 393#endif /* TICKADJ_NANO && K_TICKADJ_NAME */ 394 395#ifdef TICKADJ_NANO 396 tickadj += 999; 397 tickadj /= 1000; 398#endif 399 } 400 else 401 { 402 tickadj = 0; 403 } 404 405 if (dosync_offset != 0) 406 { 407 readvar(fd, dosync_offset, &dosynctodr); 408 } 409 410 if (noprintf_offset != 0) 411 { 412 readvar(fd, noprintf_offset, &noprintf); 413 } 414 415 (void) close(fd); 416 417 if (unsetdosync && dosync_offset == 0) 418 { 419 (void) fprintf(stderr, 420 "%s: can't find %s in namelist\n", 421 progname, 422#ifdef K_DOSYNCTODR_NAME 423 K_DOSYNCTODR_NAME 424#else /* not K_DOSYNCTODR_NAME */ 425 "dosynctodr" 426#endif /* not K_DOSYNCTODR_NAME */ 427 ); 428 exit(1); 429 } 430 431 hz = HZ; 432#if defined(HAVE_SYSCONF) && defined(_SC_CLK_TCK) 433 hz = (int) sysconf (_SC_CLK_TCK); 434#endif /* not HAVE_SYSCONF && _SC_CLK_TCK */ 435#ifdef OVERRIDE_HZ 436 hz = DEFAULT_HZ; 437#endif 438 ktick = tick; 439#ifdef PRESET_TICK 440 tick = PRESET_TICK; 441#endif /* PRESET_TICK */ 442#ifdef TICKADJ_NANO 443 tickadj /= 1000; 444 if (tickadj == 0) 445 tickadj = 1; 446#endif 447 ktickadj = tickadj; 448#ifdef PRESET_TICKADJ 449 tickadj = (PRESET_TICKADJ) ? PRESET_TICKADJ : 1; 450#endif /* PRESET_TICKADJ */ 451 452 if (!quiet) 453 { 454 if (tick_offset != 0) 455 { 456 (void) printf("KERNEL tick = %d usec (from %s kernel variable)\n", 457 ktick, 458#ifdef K_TICK_NAME 459 K_TICK_NAME 460#else 461 "<this can't happen>" 462#endif 463 ); 464 } 465#ifdef PRESET_TICK 466 (void) printf("PRESET tick = %d usec\n", tick); 467#endif /* PRESET_TICK */ 468 if (tickadj_offset != 0) 469 { 470 (void) printf("KERNEL tickadj = %d usec (from %s kernel variable)\n", 471 ktickadj, 472#ifdef K_TICKADJ_NAME 473 K_TICKADJ_NAME 474#else 475 "<this can't happen>" 476#endif 477 ); 478 } 479#ifdef PRESET_TICKADJ 480 (void) printf("PRESET tickadj = %d usec\n", tickadj); 481#endif /* PRESET_TICKADJ */ 482 if (dosync_offset != 0) 483 { 484 (void) printf("dosynctodr is %s\n", dosynctodr ? "on" : "off"); 485 } 486 if (noprintf_offset != 0) 487 { 488 (void) printf("kernel level printf's: %s\n", 489 noprintf ? "off" : "on"); 490 } 491 } 492 493 if (tick <= 0) 494 { 495 (void) fprintf(stderr, "%s: the value of tick is silly!\n", 496 progname); 497 exit(1); 498 } 499 500 hz_int = (int)(1000000L / (long)tick); 501 hz_hundredths = (int)((100000000L / (long)tick) - ((long)hz_int * 100L)); 502 if (!quiet) 503 { 504 (void) printf("KERNEL hz = %d\n", hz); 505 (void) printf("calculated hz = %d.%02d Hz\n", hz_int, 506 hz_hundredths); 507 } 508 509#if defined SCO5_CLOCK 510 recommend_tickadj = 100; 511#else /* SCO5_CLOCK */ 512 tmp = (long) tick * 500L; 513 recommend_tickadj = (int)(tmp / 1000000L); 514 if (tmp % 1000000L > 0) 515 { 516 recommend_tickadj++; 517 } 518 519#ifdef MIN_REC_TICKADJ 520 if (recommend_tickadj < MIN_REC_TICKADJ) 521 { 522 recommend_tickadj = MIN_REC_TICKADJ; 523 } 524#endif /* MIN_REC_TICKADJ */ 525#endif /* SCO5_CLOCK */ 526 527 528 if ((!quiet) && (tickadj_offset != 0)) 529 { 530 (void) printf("recommended value of tickadj = %d us\n", 531 recommend_tickadj); 532 } 533 534 if ( writetickadj == 0 535 && !writeopttickadj 536 && !unsetdosync 537 && writetick == 0 538 && !setnoprintf) 539 { 540 exit(errflg ? 1 : 0); 541 } 542 543 if (writetickadj == 0 && writeopttickadj) 544 { 545 writetickadj = recommend_tickadj; 546 } 547 548 fd = openfile(file, O_WRONLY); 549 550 if (setnoprintf && (noprintf_offset != 0)) 551 { 552 if (!quiet) 553 { 554 (void) fprintf(stderr, "setting noprintf: "); 555 (void) fflush(stderr); 556 } 557 writevar(fd, noprintf_offset, 1); 558 if (!quiet) 559 { 560 (void) fprintf(stderr, "done!\n"); 561 } 562 } 563 564 if ((writetick > 0) && (tick_offset != 0)) 565 { 566 if (!quiet) 567 { 568 (void) fprintf(stderr, "writing tick, value %d: ", 569 writetick); 570 (void) fflush(stderr); 571 } 572 writevar(fd, tick_offset, writetick); 573 if (!quiet) 574 { 575 (void) fprintf(stderr, "done!\n"); 576 } 577 } 578 579 if ((writetickadj > 0) && (tickadj_offset != 0)) 580 { 581 if (!quiet) 582 { 583 (void) fprintf(stderr, "writing tickadj, value %d: ", 584 writetickadj); 585 (void) fflush(stderr); 586 } 587 588#ifdef SCO5_CLOCK 589 /* scale from usec/tick to nsec/sec */ 590 writetickadj *= (1000L * HZ); 591#endif /* SCO5_CLOCK */ 592 593 writevar(fd, tickadj_offset, writetickadj); 594 if (!quiet) 595 { 596 (void) fprintf(stderr, "done!\n"); 597 } 598 } 599 600 if (unsetdosync && (dosync_offset != 0)) 601 { 602 if (!quiet) 603 { 604 (void) fprintf(stderr, "zeroing dosynctodr: "); 605 (void) fflush(stderr); 606 } 607 writevar(fd, dosync_offset, 0); 608 if (!quiet) 609 { 610 (void) fprintf(stderr, "done!\n"); 611 } 612 } 613 (void) close(fd); 614 return(errflg ? 1 : 0); 615} 616 617/* 618 * getoffsets - read the magic offsets from the specified file 619 */ 620static void 621getoffsets( 622 off_t *tick_off, 623 off_t *tickadj_off, 624 off_t *dosync_off, 625 off_t *noprintf_off 626 ) 627{ 628 629#ifndef NOKMEM 630# ifndef HAVE_KVM_OPEN 631 const char **kname; 632# endif 633#endif 634 635#ifndef NOKMEM 636# ifdef NLIST_NAME_UNION 637# define NL_B {{ 638# define NL_E }} 639# else 640# define NL_B { 641# define NL_E } 642# endif 643#endif 644 645#define K_FILLER_NAME "DavidLetterman" 646 647#ifdef NLIST_EXTRA_INDIRECTION 648 int i; 649#endif 650 651#ifndef NOKMEM 652 static struct nlist nl[] = 653 { 654 NL_B 655#ifdef K_TICKADJ_NAME 656#define N_TICKADJ 0 657 K_TICKADJ_NAME 658#else 659 K_FILLER_NAME 660#endif 661 NL_E, 662 NL_B 663#ifdef K_TICK_NAME 664#define N_TICK 1 665 K_TICK_NAME 666#else 667 K_FILLER_NAME 668#endif 669 NL_E, 670 NL_B 671#ifdef K_DOSYNCTODR_NAME 672#define N_DOSYNC 2 673 K_DOSYNCTODR_NAME 674#else 675 K_FILLER_NAME 676#endif 677 NL_E, 678 NL_B 679#ifdef K_NOPRINTF_NAME 680#define N_NOPRINTF 3 681 K_NOPRINTF_NAME 682#else 683 K_FILLER_NAME 684#endif 685 NL_E, 686 NL_B "" NL_E, 687 }; 688 689#ifndef HAVE_KVM_OPEN 690 static const char *kernels[] = 691 { 692#ifdef HAVE_GETBOOTFILE 693 NULL, /* *** SEE BELOW! *** */ 694#endif 695 "/kernel/unix", 696 "/kernel", 697 "/vmunix", 698 "/unix", 699 "/mach", 700 "/hp-ux", 701 "/386bsd", 702 "/netbsd", 703 "/stand/vmunix", 704 "/bsd", 705 NULL 706 }; 707#endif /* not HAVE_KVM_OPEN */ 708 709#ifdef HAVE_KVM_OPEN 710 /* 711 * Solaris > 2.5 doesn't have a kernel file. Use the kvm_* interface 712 * to read the kernel name list. -- stolcke 3/4/96 713 */ 714 kvm_t *kvm_handle = kvm_open(NULL, NULL, NULL, O_RDONLY, progname); 715 716 if (kvm_handle == NULL) 717 { 718 (void) fprintf(stderr, 719 "%s: kvm_open failed\n", 720 progname); 721 exit(1); 722 } 723 if (kvm_nlist(kvm_handle, nl) == -1) 724 { 725 (void) fprintf(stderr, 726 "%s: kvm_nlist failed\n", 727 progname); 728 exit(1); 729 } 730 kvm_close(kvm_handle); 731#else /* not HAVE_KVM_OPEN */ 732#ifdef HAVE_GETBOOTFILE /* *** SEE HERE! *** */ 733 if (kernels[0] == NULL) 734 { 735 char * cp = (char *)getbootfile(); 736 737 if (cp) 738 { 739 kernels[0] = cp; 740 } 741 else 742 { 743 kernels[0] = "/Placeholder"; 744 } 745 } 746#endif /* HAVE_GETBOOTFILE */ 747 for (kname = kernels; *kname != NULL; kname++) 748 { 749 struct stat stbuf; 750 751 if (stat(*kname, &stbuf) == -1) 752 { 753 continue; 754 } 755 if (nlist(*kname, nl) >= 0) 756 { 757 break; 758 } 759 else 760 { 761 (void) fprintf(stderr, 762 "%s: nlist didn't find needed symbols from <%s>: %s\n", 763 progname, *kname, strerror(errno)); 764 } 765 } 766 if (*kname == NULL) 767 { 768 (void) fprintf(stderr, 769 "%s: Couldn't find the kernel\n", 770 progname); 771 exit(1); 772 } 773#endif /* HAVE_KVM_OPEN */ 774 775 if (dokmem) 776 { 777 file = kmem; 778 779 fd = openfile(file, O_RDONLY); 780#ifdef NLIST_EXTRA_INDIRECTION 781 /* 782 * Go one more round of indirection. 783 */ 784 for (i = 0; i < (sizeof(nl) / sizeof(struct nlist)); i++) 785 { 786 if ((nl[i].n_value) && (nl[i].n_sclass == 0x6b)) 787 { 788 readvar(fd, nl[i].n_value, &nl[i].n_value); 789 } 790 } 791#endif /* NLIST_EXTRA_INDIRECTION */ 792 } 793#endif /* not NOKMEM */ 794 795 *tickadj_off = 0; 796 *tick_off = 0; 797 *dosync_off = 0; 798 *noprintf_off = 0; 799 800#if defined(N_TICKADJ) 801 *tickadj_off = nl[N_TICKADJ].n_value; 802#endif 803 804#if defined(N_TICK) 805 *tick_off = nl[N_TICK].n_value; 806#endif 807 808#if defined(N_DOSYNC) 809 *dosync_off = nl[N_DOSYNC].n_value; 810#endif 811 812#if defined(N_NOPRINTF) 813 *noprintf_off = nl[N_NOPRINTF].n_value; 814#endif 815 return; 816} 817 818#undef N_TICKADJ 819#undef N_TICK 820#undef N_DOSYNC 821#undef N_NOPRINTF 822 823 824/* 825 * openfile - open the file, check for errors 826 */ 827static int 828openfile( 829 const char *name, 830 int mode 831 ) 832{ 833 int ifd; 834 835 ifd = open(name, mode); 836 if (ifd < 0) 837 { 838 (void) fprintf(stderr, "%s: open %s: ", progname, name); 839 perror(""); 840 exit(1); 841 } 842 return ifd; 843} 844 845 846/* 847 * writevar - write a variable into the file 848 */ 849static void 850writevar( 851 int ofd, 852 off_t off, 853 int var 854 ) 855{ 856 857 if (lseek(ofd, off, L_SET) == -1) 858 { 859 (void) fprintf(stderr, "%s: lseek fails: ", progname); 860 perror(""); 861 exit(1); 862 } 863 if (write(ofd, (char *)&var, sizeof(int)) != sizeof(int)) 864 { 865 (void) fprintf(stderr, "%s: write fails: ", progname); 866 perror(""); 867 exit(1); 868 } 869 return; 870} 871 872 873/* 874 * readvar - read a variable from the file 875 */ 876static void 877readvar( 878 int ifd, 879 off_t off, 880 int *var 881 ) 882{ 883 int i; 884 885 if (lseek(ifd, off, L_SET) == -1) 886 { 887 (void) fprintf(stderr, "%s: lseek fails: ", progname); 888 perror(""); 889 exit(1); 890 } 891 i = read(ifd, (char *)var, sizeof(int)); 892 if (i < 0) 893 { 894 (void) fprintf(stderr, "%s: read fails: ", progname); 895 perror(""); 896 exit(1); 897 } 898 if (i != sizeof(int)) 899 { 900 (void) fprintf(stderr, "%s: read expected %d, got %d\n", 901 progname, (int)sizeof(int), i); 902 exit(1); 903 } 904 return; 905} 906#endif /* not Linux */ 907