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