xref: /netbsd-src/external/bsd/ntp/dist/adjtimed/adjtimed.c (revision cdfa2a7ef92791ba9db70a584a1d904730e6fb46)
1*cdfa2a7eSchristos /*	$NetBSD: adjtimed.c,v 1.6 2020/05/25 20:47:19 christos Exp $	*/
2abb0f93cSkardel 
3abb0f93cSkardel /*************************************************************************/
4abb0f93cSkardel /* (c) Copyright Tai Jin, 1988.  All Rights Reserved.                    */
5abb0f93cSkardel /*     Hewlett-Packard Laboratories.                                     */
6abb0f93cSkardel /*                                                                       */
7abb0f93cSkardel /* Permission is hereby granted for unlimited modification, use, and     */
8abb0f93cSkardel /* distribution.  This software is made available with no warranty of    */
9abb0f93cSkardel /* any kind, express or implied.  This copyright notice must remain      */
10abb0f93cSkardel /* intact in all versions of this software.                              */
11abb0f93cSkardel /*                                                                       */
12abb0f93cSkardel /* The author would appreciate it if any bug fixes and enhancements were */
13abb0f93cSkardel /* to be sent back to him for incorporation into future versions of this */
14abb0f93cSkardel /* software.  Please send changes to tai@iag.hp.com or ken@sdd.hp.com.   */
15abb0f93cSkardel /*************************************************************************/
16abb0f93cSkardel 
17abb0f93cSkardel #ifndef lint
18abb0f93cSkardel static char RCSid[] = "adjtimed.c,v 3.1 1993/07/06 01:04:45 jbj Exp";
19abb0f93cSkardel #endif
20abb0f93cSkardel 
21abb0f93cSkardel /*
22abb0f93cSkardel  * Adjust time daemon.
23abb0f93cSkardel  * This daemon adjusts the rate of the system clock a la BSD's adjtime().
24abb0f93cSkardel  * The adjtime() routine uses SYSV messages to communicate with this daemon.
25abb0f93cSkardel  *
26abb0f93cSkardel  * Caveat: This emulation uses an undocumented kernel variable.  As such, it
27abb0f93cSkardel  * cannot be guaranteed to work in future HP-UX releases.  Fortunately,
28abb0f93cSkardel  * it will no longer be needed in HPUX 10.01 and later.
29abb0f93cSkardel  */
30abb0f93cSkardel 
31abb0f93cSkardel #include <sys/param.h>
32abb0f93cSkardel #include <sys/types.h>
33abb0f93cSkardel #include <sys/ipc.h>
34abb0f93cSkardel #include <sys/msg.h>
35abb0f93cSkardel #include <sys/lock.h>
36abb0f93cSkardel #include <time.h>
37abb0f93cSkardel #include <signal.h>
38abb0f93cSkardel #include <nlist.h>
39abb0f93cSkardel #include <fcntl.h>
40abb0f93cSkardel #include <stdio.h>
41abb0f93cSkardel #include <unistd.h>
42abb0f93cSkardel 
43abb0f93cSkardel #include "ntp_syslog.h"
44abb0f93cSkardel #include "ntp_stdlib.h"
45abb0f93cSkardel 
46abb0f93cSkardel #include "adjtime.h"
47abb0f93cSkardel 
48abb0f93cSkardel double atof (const char *);
49abb0f93cSkardel 
50abb0f93cSkardel int InitClockRate (void);
51abb0f93cSkardel int AdjustClockRate (register struct timeval *delta, register struct timeval *olddelta);
52abb0f93cSkardel long GetClockRate (void);
53abb0f93cSkardel int SetClockRate (long);
54abb0f93cSkardel void ResetClockRate (void);
55abb0f93cSkardel void Cleanup (void);
56abb0f93cSkardel void Exit (int);
57abb0f93cSkardel 
58abb0f93cSkardel #define MILLION		1000000L
59abb0f93cSkardel 
60abb0f93cSkardel /* emacs cc-mode goes nuts if we split the next line... */
61abb0f93cSkardel #define tvtod(tv)	((double)tv.tv_sec + ((double)tv.tv_usec / (double)MILLION))
62abb0f93cSkardel 
63af12ab5eSchristos char const *progname = NULL;
64abb0f93cSkardel int verbose = 0;
65abb0f93cSkardel int sysdebug = 0;
66abb0f93cSkardel static int mqid;
67abb0f93cSkardel static double oldrate = 0.0;
68abb0f93cSkardel 
69abb0f93cSkardel int
main(int argc,char * argv[])70abb0f93cSkardel main(
71abb0f93cSkardel 	int argc,
72abb0f93cSkardel 	char *argv[]
73abb0f93cSkardel 	)
74abb0f93cSkardel {
75abb0f93cSkardel 	struct timeval remains;
76abb0f93cSkardel 	struct sigvec vec;
77abb0f93cSkardel 	MsgBuf msg;
78abb0f93cSkardel 	char ch;
79abb0f93cSkardel 	int nofork = 0;
80abb0f93cSkardel 	int fd;
81abb0f93cSkardel 
82abb0f93cSkardel 	progname = argv[0];
83abb0f93cSkardel 
84abb0f93cSkardel #ifdef LOG_LOCAL6
85abb0f93cSkardel 	openlog("adjtimed", LOG_PID, LOG_LOCAL6);
86abb0f93cSkardel #else
87abb0f93cSkardel 	openlog("adjtimed", LOG_PID);
88abb0f93cSkardel #endif
89abb0f93cSkardel 
90abb0f93cSkardel 	while ((ch = ntp_getopt(argc, argv, "hkrvdfp:")) != EOF) {
91abb0f93cSkardel 		switch (ch) {
92abb0f93cSkardel 		    case 'k':
93abb0f93cSkardel 		    case 'r':
94abb0f93cSkardel 			if ((mqid = msgget(KEY, 0)) != -1) {
95abb0f93cSkardel 				if (msgctl(mqid, IPC_RMID, (struct msqid_ds *)0) == -1) {
96abb0f93cSkardel 					msyslog(LOG_ERR, "remove old message queue: %m");
97abb0f93cSkardel 					perror("adjtimed: remove old message queue");
98abb0f93cSkardel 					exit(1);
99abb0f93cSkardel 				}
100abb0f93cSkardel 			}
101abb0f93cSkardel 
102abb0f93cSkardel 			if (ch == 'k')
103abb0f93cSkardel 			    exit(0);
104abb0f93cSkardel 
105abb0f93cSkardel 			break;
106abb0f93cSkardel 
107abb0f93cSkardel 		    case 'v':
108abb0f93cSkardel 			++verbose, nofork = 1;
109abb0f93cSkardel 			break;
110abb0f93cSkardel 
111abb0f93cSkardel 		    case 'd':
112abb0f93cSkardel 			++sysdebug;
113abb0f93cSkardel 			break;
114abb0f93cSkardel 
115abb0f93cSkardel 		    case 'f':
116abb0f93cSkardel 			nofork = 1;
117abb0f93cSkardel 			break;
118abb0f93cSkardel 
119abb0f93cSkardel 		    case 'p':
120abb0f93cSkardel 			fputs("adjtimed: -p option ignored\n", stderr);
121abb0f93cSkardel 			break;
122abb0f93cSkardel 
123abb0f93cSkardel 		    default:
124abb0f93cSkardel 			puts("usage: adjtimed -hkrvdf");
125abb0f93cSkardel 			puts("-h\thelp");
126abb0f93cSkardel 			puts("-k\tkill existing adjtimed, if any");
127abb0f93cSkardel 			puts("-r\trestart (kills existing adjtimed, if any)");
128abb0f93cSkardel 			puts("-v\tdebug output (repeat for more output)");
129abb0f93cSkardel 			puts("-d\tsyslog output (repeat for more output)");
130abb0f93cSkardel 			puts("-f\tno fork");
131abb0f93cSkardel 			msyslog(LOG_ERR, "usage error");
132abb0f93cSkardel 			exit(1);
133abb0f93cSkardel 		} /* switch */
134abb0f93cSkardel 	} /* while */
135abb0f93cSkardel 
136abb0f93cSkardel 	if (!nofork) {
137abb0f93cSkardel 		switch (fork()) {
138abb0f93cSkardel 		    case 0:
139abb0f93cSkardel 			close(fileno(stdin));
140abb0f93cSkardel 			close(fileno(stdout));
141abb0f93cSkardel 			close(fileno(stderr));
142abb0f93cSkardel 
143abb0f93cSkardel #ifdef TIOCNOTTY
144abb0f93cSkardel 			if ((fd = open("/dev/tty")) != -1) {
145abb0f93cSkardel 				ioctl(fd, TIOCNOTTY, 0);
146abb0f93cSkardel 				close(fd);
147abb0f93cSkardel 			}
148abb0f93cSkardel #else
149abb0f93cSkardel 			setpgrp();
150abb0f93cSkardel #endif
151abb0f93cSkardel 			break;
152abb0f93cSkardel 
153abb0f93cSkardel 		    case -1:
154abb0f93cSkardel 			msyslog(LOG_ERR, "fork: %m");
155abb0f93cSkardel 			perror("adjtimed: fork");
156abb0f93cSkardel 			exit(1);
157abb0f93cSkardel 
158abb0f93cSkardel 		    default:
159abb0f93cSkardel 			exit(0);
160abb0f93cSkardel 		} /* switch */
161abb0f93cSkardel 	} /* if */
162abb0f93cSkardel 
163abb0f93cSkardel 	if (nofork) {
164abb0f93cSkardel 		setvbuf(stdout, NULL, _IONBF, BUFSIZ);
165abb0f93cSkardel 		setvbuf(stderr, NULL, _IONBF, BUFSIZ);
166abb0f93cSkardel 	}
167abb0f93cSkardel 
168abb0f93cSkardel 	msyslog(LOG_INFO, "started");
169abb0f93cSkardel 	if (verbose) printf("adjtimed: started\n");
170abb0f93cSkardel 
171abb0f93cSkardel 	if (InitClockRate() == -1)
172abb0f93cSkardel 	    Exit(2);
173abb0f93cSkardel 
174abb0f93cSkardel 	(void)signal(SIGHUP, SIG_IGN);
175abb0f93cSkardel 	(void)signal(SIGINT, SIG_IGN);
176abb0f93cSkardel 	(void)signal(SIGQUIT, SIG_IGN);
177abb0f93cSkardel 	(void)signal(SIGTERM, Cleanup);
178abb0f93cSkardel 
179abb0f93cSkardel 	vec.sv_handler = ResetClockRate;
180abb0f93cSkardel 	vec.sv_flags = 0;
181abb0f93cSkardel 	vec.sv_mask = ~0;
182abb0f93cSkardel 	sigvector(SIGALRM, &vec, (struct sigvec *)0);
183abb0f93cSkardel 
184abb0f93cSkardel 	if (msgget(KEY, IPC_CREAT|IPC_EXCL) == -1) {
185abb0f93cSkardel 		if (errno == EEXIST) {
186abb0f93cSkardel 			msyslog(LOG_ERR, "message queue already exists, use -r to remove it");
187abb0f93cSkardel 			fputs("adjtimed: message queue already exists, use -r to remove it\n",
188abb0f93cSkardel 			      stderr);
189abb0f93cSkardel 			Exit(1);
190abb0f93cSkardel 		}
191abb0f93cSkardel 
192abb0f93cSkardel 		msyslog(LOG_ERR, "create message queue: %m");
193abb0f93cSkardel 		perror("adjtimed: create message queue");
194abb0f93cSkardel 		Exit(1);
195abb0f93cSkardel 	}
196abb0f93cSkardel 
197abb0f93cSkardel 	if ((mqid = msgget(KEY, 0)) == -1) {
198abb0f93cSkardel 		msyslog(LOG_ERR, "get message queue id: %m");
199abb0f93cSkardel 		perror("adjtimed: get message queue id");
200abb0f93cSkardel 		Exit(1);
201abb0f93cSkardel 	}
202abb0f93cSkardel 
203abb0f93cSkardel 	/* Lock process in memory to improve response time */
204abb0f93cSkardel 	if (plock(PROCLOCK)) {
205abb0f93cSkardel 		msyslog(LOG_ERR, "plock: %m");
206abb0f93cSkardel 		perror("adjtimed: plock");
207abb0f93cSkardel 		Cleanup();
208abb0f93cSkardel 	}
209abb0f93cSkardel 
210abb0f93cSkardel 	/* Also raise process priority.
211abb0f93cSkardel 	 * If we do not get run when we want, this leads to bad timekeeping
212abb0f93cSkardel 	 * and "Previous time adjustment didn't complete" gripes from xntpd.
213abb0f93cSkardel 	 */
214abb0f93cSkardel 	if (nice(-10) == -1) {
215abb0f93cSkardel 		msyslog(LOG_ERR, "nice: %m");
216abb0f93cSkardel 		perror("adjtimed: nice");
217abb0f93cSkardel 		Cleanup();
218abb0f93cSkardel 	}
219abb0f93cSkardel 
220abb0f93cSkardel 	for (;;) {
221abb0f93cSkardel 		if (msgrcv(mqid, &msg.msgp, MSGSIZE, CLIENT, 0) == -1) {
222abb0f93cSkardel 			if (errno == EINTR) continue;
223abb0f93cSkardel 			msyslog(LOG_ERR, "read message: %m");
224abb0f93cSkardel 			perror("adjtimed: read message");
225abb0f93cSkardel 			Cleanup();
226abb0f93cSkardel 		}
227abb0f93cSkardel 
228abb0f93cSkardel 		switch (msg.msgb.code) {
229abb0f93cSkardel 		    case DELTA1:
230abb0f93cSkardel 		    case DELTA2:
231abb0f93cSkardel 			AdjustClockRate(&msg.msgb.tv, &remains);
232abb0f93cSkardel 
233abb0f93cSkardel 			if (msg.msgb.code == DELTA2) {
234abb0f93cSkardel 				msg.msgb.tv = remains;
235abb0f93cSkardel 				msg.msgb.mtype = SERVER;
236abb0f93cSkardel 
237abb0f93cSkardel 				while (msgsnd(mqid, &msg.msgp, MSGSIZE, 0) == -1) {
238abb0f93cSkardel 					if (errno == EINTR) continue;
239abb0f93cSkardel 					msyslog(LOG_ERR, "send message: %m");
240abb0f93cSkardel 					perror("adjtimed: send message");
241abb0f93cSkardel 					Cleanup();
242abb0f93cSkardel 				}
243abb0f93cSkardel 			}
244abb0f93cSkardel 
245abb0f93cSkardel 			if (remains.tv_sec + remains.tv_usec != 0L) {
246abb0f93cSkardel 				if (verbose) {
247abb0f93cSkardel 					printf("adjtimed: previous correction remaining %.6fs\n",
248abb0f93cSkardel 					       tvtod(remains));
249abb0f93cSkardel 				}
250abb0f93cSkardel 				if (sysdebug) {
251abb0f93cSkardel 					msyslog(LOG_INFO, "previous correction remaining %.6fs",
252abb0f93cSkardel 						tvtod(remains));
253abb0f93cSkardel 				}
254abb0f93cSkardel 			}
255abb0f93cSkardel 			break;
256abb0f93cSkardel 
257abb0f93cSkardel 		    default:
258abb0f93cSkardel 			fprintf(stderr, "adjtimed: unknown message code %d\n", msg.msgb.code);
259abb0f93cSkardel 			msyslog(LOG_ERR, "unknown message code %d", msg.msgb.code);
260abb0f93cSkardel 		} /* switch */
261abb0f93cSkardel 	} /* loop */
262abb0f93cSkardel } /* main */
263abb0f93cSkardel 
264abb0f93cSkardel /*
265abb0f93cSkardel  * Default clock rate (old_tick).
266abb0f93cSkardel  */
267abb0f93cSkardel #define DEFAULT_RATE	(MILLION / HZ)
268abb0f93cSkardel #define UNKNOWN_RATE	0L
269abb0f93cSkardel #define TICK_ADJ	5	/* standard adjustment rate, microsec/tick */
270abb0f93cSkardel 
271abb0f93cSkardel static long default_rate = DEFAULT_RATE;
272abb0f93cSkardel static long tick_rate = HZ;	/* ticks per sec */
273abb0f93cSkardel static long slew_rate = TICK_ADJ * HZ; /* in microsec/sec */
274abb0f93cSkardel 
275abb0f93cSkardel int
AdjustClockRate(register struct timeval * delta,register struct timeval * olddelta)276abb0f93cSkardel AdjustClockRate(
277abb0f93cSkardel 	register struct timeval *delta,
278abb0f93cSkardel 	register struct timeval *olddelta
279abb0f93cSkardel 	)
280abb0f93cSkardel {
281abb0f93cSkardel 	register long rate, dt, leftover;
282abb0f93cSkardel 	struct itimerval period, remains;
283abb0f93cSkardel 
284abb0f93cSkardel 	dt = (delta->tv_sec * MILLION) + delta->tv_usec;
285abb0f93cSkardel 
286abb0f93cSkardel 	if (verbose)
287abb0f93cSkardel 	    printf("adjtimed: new correction %.6fs\n", (double)dt / (double)MILLION);
288abb0f93cSkardel 	if (sysdebug)
289abb0f93cSkardel 	    msyslog(LOG_INFO, "new correction %.6fs", (double)dt / (double)MILLION);
290abb0f93cSkardel 	if (verbose > 2) printf("adjtimed: leftover %ldus\n", leftover);
291abb0f93cSkardel 	if (sysdebug > 2) msyslog(LOG_INFO, "leftover %ldus", leftover);
292abb0f93cSkardel 	rate = dt;
293abb0f93cSkardel 
294abb0f93cSkardel 	/*
295abb0f93cSkardel 	 * Apply a slew rate of slew_rate over a period of dt/slew_rate seconds.
296abb0f93cSkardel 	 */
297abb0f93cSkardel 	if (dt > 0) {
298abb0f93cSkardel 		rate = slew_rate;
299abb0f93cSkardel 	} else {
300abb0f93cSkardel 		rate = -slew_rate;
301abb0f93cSkardel 		dt = -dt;
302abb0f93cSkardel 	}
303abb0f93cSkardel 	period.it_value.tv_sec = dt / slew_rate;
304abb0f93cSkardel 	period.it_value.tv_usec = (dt % slew_rate) * (MILLION / slew_rate);
305abb0f93cSkardel 	/*
306abb0f93cSkardel 	 * Note: we assume the kernel will convert the specified period into ticks
307abb0f93cSkardel 	 * using the modified clock rate rather than an assumed nominal clock rate,
308abb0f93cSkardel 	 * and therefore will generate the timer interrupt after the specified
309abb0f93cSkardel 	 * number of true seconds, not skewed seconds.
310abb0f93cSkardel 	 */
311abb0f93cSkardel 
312abb0f93cSkardel 	if (verbose > 1)
313abb0f93cSkardel 	    printf("adjtimed: will be complete in %lds %ldus\n",
314abb0f93cSkardel 		   period.it_value.tv_sec, period.it_value.tv_usec);
315abb0f93cSkardel 	if (sysdebug > 1)
316abb0f93cSkardel 	    msyslog(LOG_INFO, "will be complete in %lds %ldus",
317abb0f93cSkardel 		    period.it_value.tv_sec, period.it_value.tv_usec);
318abb0f93cSkardel 	/*
319abb0f93cSkardel 	 * adjust the clock rate
320abb0f93cSkardel 	 */
321abb0f93cSkardel 	if (dt) {
322abb0f93cSkardel 		if (SetClockRate((rate / tick_rate) + default_rate) == -1) {
323abb0f93cSkardel 			msyslog(LOG_ERR, "set clock rate: %m");
324abb0f93cSkardel 			perror("adjtimed: set clock rate");
325abb0f93cSkardel 		}
326abb0f93cSkardel 	}
327abb0f93cSkardel 	/*
328abb0f93cSkardel 	 * start the timer
329abb0f93cSkardel 	 * (do this after changing the rate because the period has been rounded down)
330abb0f93cSkardel 	 */
331abb0f93cSkardel 	period.it_interval.tv_sec = period.it_interval.tv_usec = 0L;
332abb0f93cSkardel 	setitimer(ITIMER_REAL, &period, &remains);
333abb0f93cSkardel 	/*
334abb0f93cSkardel 	 * return old delta
335abb0f93cSkardel 	 */
336abb0f93cSkardel 	if (olddelta) {
337abb0f93cSkardel 		dt = ((remains.it_value.tv_sec * MILLION) + remains.it_value.tv_usec) *
338abb0f93cSkardel 			oldrate;
339abb0f93cSkardel 		olddelta->tv_sec = dt / MILLION;
340abb0f93cSkardel 		olddelta->tv_usec = dt - (olddelta->tv_sec * MILLION);
341abb0f93cSkardel 	}
342abb0f93cSkardel 
343abb0f93cSkardel 	oldrate = (double)rate / (double)MILLION;
344abb0f93cSkardel 	return(0);
345abb0f93cSkardel } /* AdjustClockRate */
346abb0f93cSkardel 
347abb0f93cSkardel static struct nlist nl[] = {
348abb0f93cSkardel #ifdef __hp9000s800
349abb0f93cSkardel #ifdef PRE7_0
350abb0f93cSkardel 	{ "tick" },
351abb0f93cSkardel #else
352abb0f93cSkardel 	{ "old_tick" },
353abb0f93cSkardel #endif
354abb0f93cSkardel #else
355abb0f93cSkardel 	{ "_old_tick" },
356abb0f93cSkardel #endif
357abb0f93cSkardel 	{ "" }
358abb0f93cSkardel };
359abb0f93cSkardel 
360abb0f93cSkardel static int kmem;
361abb0f93cSkardel 
362abb0f93cSkardel /*
363abb0f93cSkardel  * The return value is the clock rate in old_tick units or -1 if error.
364abb0f93cSkardel  */
365abb0f93cSkardel long
GetClockRate(void)366abb0f93cSkardel GetClockRate(void)
367abb0f93cSkardel {
368abb0f93cSkardel 	long rate, mask;
369abb0f93cSkardel 
370abb0f93cSkardel 	if (lseek(kmem, (off_t)nl[0].n_value, 0) == -1L)
371abb0f93cSkardel 	    return (-1L);
372abb0f93cSkardel 
373abb0f93cSkardel 	mask = sigblock(sigmask(SIGALRM));
374abb0f93cSkardel 
375abb0f93cSkardel 	if (read(kmem, (caddr_t)&rate, sizeof(rate)) != sizeof(rate))
376abb0f93cSkardel 	    rate = UNKNOWN_RATE;
377abb0f93cSkardel 
378abb0f93cSkardel 	sigsetmask(mask);
379abb0f93cSkardel 	return (rate);
380abb0f93cSkardel } /* GetClockRate */
381abb0f93cSkardel 
382abb0f93cSkardel /*
383abb0f93cSkardel  * The argument is the new rate in old_tick units.
384abb0f93cSkardel  */
385abb0f93cSkardel int
SetClockRate(long rate)386abb0f93cSkardel SetClockRate(
387abb0f93cSkardel 	long rate
388abb0f93cSkardel 	)
389abb0f93cSkardel {
390abb0f93cSkardel 	long mask;
391abb0f93cSkardel 
392abb0f93cSkardel 	if (lseek(kmem, (off_t)nl[0].n_value, 0) == -1L)
393abb0f93cSkardel 	    return (-1);
394abb0f93cSkardel 
395abb0f93cSkardel 	mask = sigblock(sigmask(SIGALRM));
396abb0f93cSkardel 
397abb0f93cSkardel 	if (write(kmem, (caddr_t)&rate, sizeof(rate)) != sizeof(rate)) {
398abb0f93cSkardel 		sigsetmask(mask);
399abb0f93cSkardel 		return (-1);
400abb0f93cSkardel 	}
401abb0f93cSkardel 
402abb0f93cSkardel 	sigsetmask(mask);
403abb0f93cSkardel 
404abb0f93cSkardel 	if (rate != default_rate) {
405abb0f93cSkardel 		if (verbose > 3) {
406abb0f93cSkardel 			printf("adjtimed: clock rate (%lu) %ldus/s\n", rate,
407abb0f93cSkardel 			       (rate - default_rate) * tick_rate);
408abb0f93cSkardel 		}
409abb0f93cSkardel 		if (sysdebug > 3) {
410abb0f93cSkardel 			msyslog(LOG_INFO, "clock rate (%lu) %ldus/s", rate,
411abb0f93cSkardel 				(rate - default_rate) * tick_rate);
412abb0f93cSkardel 		}
413abb0f93cSkardel 	}
414abb0f93cSkardel 
415abb0f93cSkardel 	return (0);
416abb0f93cSkardel } /* SetClockRate */
417abb0f93cSkardel 
418abb0f93cSkardel int
InitClockRate(void)419abb0f93cSkardel InitClockRate(void)
420abb0f93cSkardel {
421abb0f93cSkardel 	if ((kmem = open("/dev/kmem", O_RDWR)) == -1) {
422abb0f93cSkardel 		msyslog(LOG_ERR, "open(/dev/kmem): %m");
423abb0f93cSkardel 		perror("adjtimed: open(/dev/kmem)");
424abb0f93cSkardel 		return (-1);
425abb0f93cSkardel 	}
426abb0f93cSkardel 
427abb0f93cSkardel 	nlist("/hp-ux", nl);
428abb0f93cSkardel 
429abb0f93cSkardel 	if (nl[0].n_type == 0) {
430abb0f93cSkardel 		fputs("adjtimed: /hp-ux has no symbol table\n", stderr);
431abb0f93cSkardel 		msyslog(LOG_ERR, "/hp-ux has no symbol table");
432abb0f93cSkardel 		return (-1);
433abb0f93cSkardel 	}
434abb0f93cSkardel 	/*
435abb0f93cSkardel 	 * Set the default to the system's original value
436abb0f93cSkardel 	 */
437abb0f93cSkardel 	default_rate = GetClockRate();
438abb0f93cSkardel 	if (default_rate == UNKNOWN_RATE) default_rate = DEFAULT_RATE;
439abb0f93cSkardel 	tick_rate = (MILLION / default_rate);
440abb0f93cSkardel 	slew_rate = TICK_ADJ * tick_rate;
441abb0f93cSkardel 	fprintf(stderr,"default_rate=%ld, tick_rate=%ld, slew_rate=%ld\n",default_rate,tick_rate,slew_rate);
442abb0f93cSkardel 
443abb0f93cSkardel 	return (0);
444abb0f93cSkardel } /* InitClockRate */
445abb0f93cSkardel 
446abb0f93cSkardel /*
447abb0f93cSkardel  * Reset the clock rate to the default value.
448abb0f93cSkardel  */
449abb0f93cSkardel void
ResetClockRate(void)450abb0f93cSkardel ResetClockRate(void)
451abb0f93cSkardel {
452abb0f93cSkardel 	struct itimerval it;
453abb0f93cSkardel 
454abb0f93cSkardel 	it.it_value.tv_sec = it.it_value.tv_usec = 0L;
455abb0f93cSkardel 	setitimer(ITIMER_REAL, &it, (struct itimerval *)0);
456abb0f93cSkardel 
457abb0f93cSkardel 	if (verbose > 2) puts("adjtimed: resetting the clock");
458abb0f93cSkardel 	if (sysdebug > 2) msyslog(LOG_INFO, "resetting the clock");
459abb0f93cSkardel 
460abb0f93cSkardel 	if (GetClockRate() != default_rate) {
461abb0f93cSkardel 		if (SetClockRate(default_rate) == -1) {
462abb0f93cSkardel 			msyslog(LOG_ERR, "set clock rate: %m");
463abb0f93cSkardel 			perror("adjtimed: set clock rate");
464abb0f93cSkardel 		}
465abb0f93cSkardel 	}
466abb0f93cSkardel 
467abb0f93cSkardel 	oldrate = 0.0;
468abb0f93cSkardel } /* ResetClockRate */
469abb0f93cSkardel 
470abb0f93cSkardel void
Cleanup(void)471abb0f93cSkardel Cleanup(void)
472abb0f93cSkardel {
473abb0f93cSkardel 	ResetClockRate();
474abb0f93cSkardel 
475abb0f93cSkardel 	if (msgctl(mqid, IPC_RMID, (struct msqid_ds *)0) == -1) {
476abb0f93cSkardel 		if (errno != EINVAL) {
477abb0f93cSkardel 			msyslog(LOG_ERR, "remove message queue: %m");
478abb0f93cSkardel 			perror("adjtimed: remove message queue");
479abb0f93cSkardel 		}
480abb0f93cSkardel 	}
481abb0f93cSkardel 
482abb0f93cSkardel 	Exit(2);
483abb0f93cSkardel } /* Cleanup */
484abb0f93cSkardel 
485abb0f93cSkardel void
Exit(status)486abb0f93cSkardel Exit(status)
487abb0f93cSkardel      int status;
488abb0f93cSkardel {
489abb0f93cSkardel 	msyslog(LOG_ERR, "terminated");
490abb0f93cSkardel 	closelog();
491abb0f93cSkardel 	if (kmem != -1) close(kmem);
492abb0f93cSkardel 	exit(status);
493abb0f93cSkardel } /* Exit */
494