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