Files
n/main.c
2018-12-20 10:55:42 +01:00

152 lines
3.6 KiB
C

#include <getopt.h>
#include <netdb.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>
#define EPOCH 2208988800ull
// assumes either little or big endian. pdp-endian, youre out of luck
#define NLITTLE 0x41424344UL
#define NENDIAN ('ABCD')
typedef struct {
#if NENDIAN == NLITTLE
unsigned int mode: 3;
unsigned int vn: 3;
unsigned int li: 2;
#else
unsigned int li: 2;
unsigned int vn: 3;
unsigned int mode: 3;
#endif
uint8_t stratum;
uint8_t poll;
uint8_t prec;
uint32_t delay;
uint32_t dispersion;
uint32_t refid;
uint32_t rtms;
uint32_t rtmf;
uint32_t otms;
uint32_t otmf;
uint32_t rctms;
uint32_t rctmf;
uint32_t ttms;
uint32_t ttmf;
} ntp;
typedef struct {
const char* host;
int port;
const char* format;
} ntp_info;
ntp_info NDEFAULT = {.host="europe.pool.ntp.org", .port = 123, .format = NULL};
char* nstrftime(const char* fmt, const struct tm* t) {
int size = 40;
char* res = malloc(size);
int n;
do {
n = strftime(res, size-1, fmt, t);
size *= 2;
} while (!n);
return res;
}
void err(const char* msg) {
fprintf(stderr, "Error %s.\n", msg);
exit(1);
}
void usage(const char* program, int code) {
fprintf(stderr, "Usage: %s [options]\n", program);
fputs("Options:\n", stderr);
fputs(" -h HOST, --host=HOST NTP server to use\n", stderr);
fputs(" defaults to 'europe.pool.ntp.org'\n", stderr);
fputs(" -p PORT, --port=PORT NTP server port to use (must be numerical)\n", stderr);
fputs(" defaults to '123'\n", stderr);
fputs(" -f FORMAT, --format=FORMAT Date format string (passed to strftime)\n", stderr);
fputs(" defaults to standard of ctime\n", stderr);
fputs(" --help Display this message and exit\n", stderr);
exit(code);
}
ntp_info args(int argc, char** argv) {
char c;
ntp_info res = NDEFAULT;
static struct option long_options[] = {
{"host", required_argument, 0, 'h'},
{"port", required_argument, 0, 'p'},
{"format", required_argument, 0, 'f'},
{"help", no_argument, 0, 'u'},
{NULL, 0, NULL, 0}
};
while ((c = getopt_long(argc, argv, "t:a:f:", long_options, 0)) != -1) {
switch (c) {
case 'h': res.host = optarg; break;
case 'f': res.format = optarg; break;
case 'p': {
char* end;
res.port = strtol(optarg, &end, 10);
if (end[0] != 0) {
fputs("Port is not numerical.\n", stderr);
usage(argv[0], 1);
}
break;
}
case 'u': usage(argv[0], 0);
default: usage(argv[0], 1);
}
}
return res;
}
int main(int argc, char** argv) {
int sock;
ntp n;
struct sockaddr_in a;
struct hostent* s;
ntp_info i = args(argc, argv);
memset(&n, 0, sizeof(ntp));
n.vn = 3;
n.mode = 3;
sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (sock < 0) err("opening socket");
s = gethostbyname(i.host);
if (!s) err("resolving host");
bzero(&a, sizeof(a));
a.sin_family = AF_INET;
a.sin_port = htons(i.port);
bcopy(s->h_addr, &a.sin_addr.s_addr, s->h_length);
if (connect(sock, (struct sockaddr *) &a, sizeof(a)) < 0) err("connecting");
if (write(sock, &n, sizeof(ntp)) < 0) err("writing to network");
if (read(sock, &n, sizeof(ntp)) < 0) err("reading from network");
n.ttms = ntohl(n.ttms);
time_t tm = n.ttms - EPOCH;
if (!i.format) {
fputs(ctime(&tm), stdout);
} else {
char* fmt = nstrftime(i.format, localtime(&tm));
puts(fmt);
free(fmt);
}
return 0;
}