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