source: trunk/athena/etc/gettime/gettime.c @ 13764

Revision 13764, 6.1 KB checked in by danw, 25 years ago (diff)
autoconf/cleanup/warns
Line 
1/* Copyright 1985-1999 by the Massachusetts Institute of Technology.
2 *
3 * Permission to use, copy, modify, and distribute this
4 * software and its documentation for any purpose and without
5 * fee is hereby granted, provided that the above copyright
6 * notice appear in all copies and that both that copyright
7 * notice and this permission notice appear in supporting
8 * documentation, and that the name of M.I.T. not be used in
9 * advertising or publicity pertaining to distribution of the
10 * software without specific, written prior permission.
11 * M.I.T. makes no representations about the suitability of
12 * this software for any purpose.  It is provided "as is"
13 * without express or implied warranty.
14 */
15
16/* Retrieve the time from a remote host and print it in ctime(3)
17 * format. The time is acquired via the protocol described in
18 * RFC868. The name of the host to be queried is specified on the
19 * command line, and if the -s option is also specified, and gettime
20 * is run as root, the clock on the local workstation will also be
21 * set. gettime makes five attempts at getting the time, each with
22 * a five second timeout.
23 */
24
25static const char rcsid[] = "$Id: gettime.c,v 1.15 1999-10-18 17:20:15 danw Exp $";
26
27#include <stdio.h>
28#include <stdlib.h>
29#include <string.h>
30#include <unistd.h>
31#include <time.h>
32#include <errno.h>
33#include <sys/types.h>
34#include <sys/socket.h>
35#include <sys/time.h>
36#include <netinet/in.h>
37#include <netdb.h>
38
39#define UNIX_OFFSET_TO_1900 ((70 * 365UL + 17) * 24 * 60 * 60)
40#define TIME_SERVICE "time"
41#define MAX_TRIES 5
42#define TIMEOUT 5
43
44int main(int argc, char **argv)
45{
46  struct servent *service_info;
47  struct hostent *host_info = NULL;
48  struct sockaddr_in time_address;
49  char *time_hostname;
50  unsigned char buffer[20];
51  int tries, time_socket, result;
52  fd_set read_set;
53  struct timeval timeout, current_time;
54  struct timezone current_timezone;
55  time_t now;
56  int c, setflag = 0, errflag = 0;
57  int granularity = 0;
58  char *program_name;
59
60  /* Set up our program name. */
61  program_name = strrchr(argv[0], '/');
62  if (program_name != NULL)
63    program_name++;
64  else
65    program_name = argv[0];
66
67  /* Parse arguments. */
68  while ((c = getopt(argc, argv, "sg:")) != -1)
69    {
70      switch (c)
71        {
72        case 's':
73          setflag = 1;
74          break;
75        case 'g':
76          granularity = atoi(optarg);
77          break;
78        case '?':
79          errflag = 1;
80          break;
81        }
82    }
83
84  if (errflag || optind + 1 != argc)
85    {
86      fprintf(stderr, "usage: %s [-g granularity] [-s] hostname\n",
87              program_name);
88      exit(1);
89    }
90
91  time_hostname = argv[optind];
92
93  /* Look up port number for time service. */
94  service_info = getservbyname(TIME_SERVICE, "udp");
95  if (service_info == NULL)
96    {
97      fprintf(stderr, "%s: " TIME_SERVICE "/udp: unknown service\n",
98              program_name);
99      exit(1);
100    }
101
102  /* Resolve hostname (try MAX_TRIES times). We do this in case the
103   * nameserver is just starting up (as in, everyone is just rebooting
104   * from a long power failure, and we are requesting name resolution
105   * before the server is ready).
106   */
107  for (tries = 0; tries < MAX_TRIES; tries++)
108    {
109      host_info = gethostbyname(time_hostname);
110      if (host_info != NULL || (host_info == NULL && h_errno != TRY_AGAIN))
111        break;
112    }
113
114  if (host_info == NULL)
115    {
116      fprintf(stderr, "%s: host %s unknown\n", program_name, time_hostname);
117      exit(1);
118    }
119
120  if (host_info->h_addrtype != AF_INET)
121    {
122      fprintf(stderr, "%s: can't handle address type %d\n",
123              program_name, host_info->h_addrtype);
124      exit(1);
125    }
126
127  /* Grab a socket. */
128  time_socket = socket(AF_INET, SOCK_DGRAM, 0);
129  if (time_socket < 0)
130    {
131      fprintf(stderr, "%s: can't create socket: %s\n",
132              program_name, strerror(errno));
133      exit(1);
134    }
135
136  /* Set up destination address. */
137  time_address.sin_family = AF_INET;
138  memcpy(&time_address.sin_addr, host_info->h_addr,
139         sizeof(time_address.sin_addr));
140  time_address.sin_port = service_info->s_port;
141
142  /* "Connect" the UDP socket to the time server address. */
143  if (connect(time_socket, (struct sockaddr *)&time_address,
144              sizeof(time_address)) < 0)
145    {
146      fprintf(stderr, "%s: can't connect: %s\n", program_name,
147              strerror(errno));
148      exit(1);
149    }
150
151  /* Initialize info for select. */
152  FD_ZERO(&read_set);
153
154  /* Attempt to acquire the time MAX_TRIES times at TIMEOUT interval. */
155  for (tries = 0; tries < MAX_TRIES; tries++)
156    {
157      /* Just send an empty packet. */
158      send(time_socket, buffer, 0, 0);
159
160      /* Wait a little while for a reply. */
161      FD_SET(time_socket, &read_set);
162      timeout.tv_sec = TIMEOUT;
163      timeout.tv_usec = 0;
164      result = select(time_socket + 1, &read_set, NULL, NULL, &timeout);
165
166      if (result == 0)          /* timed out, resend... */
167        continue;
168
169      if (result < 0)           /* error from select */
170        {
171          fprintf(stderr, "%s: select: %s\n", program_name, strerror(errno));
172          exit(1);
173        }
174
175      /* There must be data available. */
176      result = recv(time_socket, buffer, sizeof(buffer), 0);
177      if (result < 0)
178        {
179          fprintf(stderr, "%s: receive failed: %s\n", program_name,
180                  strerror(errno));
181          exit(1);
182        }         
183
184      /* We should have received exactly four bytes in the packet. */
185      if (result == 4)
186        break;
187
188      fprintf(stderr, "%s: received %d bytes, expected 4\n", program_name,
189              result);
190      exit(1);
191    }
192
193  if (tries == MAX_TRIES)
194    {
195      fprintf(stderr, "%s: Failed to get time from %s.\n", program_name,
196              time_hostname);
197      exit(1);
198    }
199
200  /* Convert RFC868 time to Unix time, and print it. */
201  now = (time_t)(((buffer[0] << 24) | (buffer[1] << 16) |
202                  (buffer[2] << 8) | buffer[3])
203                 - UNIX_OFFSET_TO_1900);
204  fprintf(stdout, "%s", ctime(&now));
205
206  /* Set the time if requested. */
207  if (setflag)
208    {
209      gettimeofday(&current_time, &current_timezone);
210
211      if (current_time.tv_sec < now - granularity
212          || current_time.tv_sec >= now + granularity)
213        {
214          current_time.tv_sec = now;
215          current_time.tv_usec = 0;
216          if (settimeofday(&current_time, &current_timezone) < 0)
217            {
218              fprintf(stderr, "%s: can't set time: %s\n",
219                      program_name, strerror(errno));
220              exit(1);
221            }
222        }
223    }
224
225  return 0;
226}
Note: See TracBrowser for help on using the repository browser.