Listing 1: setime.c
Sets the system date/time retrieved from a server in
TCP/IP-based network.
/*
* This program sets the system date/time retrieved from a server in a TCP/IP
* based network.
*
* Usage: setime <node name> <time interval in hours>
*
* 1) Setup the datagram socket
* 2) Get the hostname
* 3) Set the optional time interval
* 4) Send the daytime datagram to the server
* 5) Set the timeout alarm
* 6) Receive the daytime string back from the server
* 7) Time out if a response doesn't arrive in 20 seconds
* 8) Parse the returned date time string
* 9) Set the time tm structure
*10) If the new time is within range parameter, set the system
* date and time
*/
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <string.h>
#include <time.h>
#include <errno.h>
#include <signal.h>
#define BUFSZ 256
#define SERVICE "daytime"
#define is_uppercase(x) ((x >= 'A' && x <= 'Z') ? 1 : 0)
#define to_lowercase(x) ((is_uppercase(x)) ? x + 'a' - 'A' : x)
main(argc, argv)
int argc;
char **argv;
{
int s, n, len, dayno, mono, hrno, minno, yearno, secno, chkno, chksec;
double timedif;
char buf[BUFSZ], *daystr, *monstr, *nostr, *timestr, *yearstr, *hrstr, *minstr,
*secstr, *chkhrstr;
struct hostent *hp;
struct servent *sp;
struct sockaddr_in sin;
time_t tloc, caltime;
struct tm *old, new;
extern int timedout();
/* get a datagram in the Internet domain. */
if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
{
fprintf(stderr, "socket error");
exit (1);
}
/* lookup the port number of the daytime service */
if ((sp = getservbyname(SERVICE, "udp")) == NULL)
{
fprintf(stderr, "upd %s: unknown service.\n", SERVICE);
exit (1);
}
/* get the server from the command line */
if ((hp = gethostbyname(*++argv)) == NULL)
{
fprintf(stderr, "%s: server unknown.\n", *argv);
exit (1);
}
/* get the time range parameter */
if ((chkhrstr = *++argv) == NULL)
{
chkno = 24;
chksec = 86400; /* seconds in 24 hours */
}
else /* default to 24 hours */
{
chkno = atoi(chkhrstr);
chksec = chkno * 3600; /* seconds in an an hour */
if(chksec < 0)
chksec = chksec * (-1);
}
/* build the address of the server on the client machine */
sin.sin_family = AF_INET;
sin.sin_port = sp->s_port;
bcopy(hp->h_addr, &sin.sin_addr, hp->h_length);
/* send datagram to server */
if (sendto(s, buf, BUFSZ, 0, &sin, sizeof(sin)) < 0)
{
fprintf(stderr, "sendto error");
exit (1);
}
/* set the alarm for 20 seconds */
signal(SIGALRM, timedout);
alarm(20);
/* receive a datagram */
len = sizeof(sin);
n = recvfrom(s, buf, sizeof(buf), 0, &sin, &len);
alarm(0); /* turn off the alarm */
if (n < 0)
{
fprintf(stderr, "recvfrom error");
exit (1);
}
/* terminate the returned datagram string */
buf[n] = NULL;
close(s);
/* parse the returned date string */
daystr = strtok(buf," ");
monstr = strtok(NULL," ");
nostr = strtok(NULL," ");
timestr = strtok(NULL," ");
yearstr = strtok(NULL," ");
hrstr = strtok(timestr,":");
minstr = strtok(NULL,":");
secstr = strtok(NULL,":");
/* convert date and time strings to integer */
dayno = atoi(nostr);
hrno = atoi(hrstr);
minno = atoi(minstr);
secno = atoi(secstr);
yearno = atoi(yearstr);
mono = retmonth(monstr);
/* set the time */
time(&tloc);
old = localtime(&tloc);
new.tm_year = yearno - 1900;
new.tm_mon = mono - 1;
new.tm_mday = dayno;
new.tm_hour = hrno;
new.tm_min = minno;
new.tm_sec = secno;
new.tm_isdst = old->tm_isdst;
caltime = mktime(&new);
timedif = difftime(tloc, caltime);
if(timedif < 0) /* don't care if time change is negative */
timedif = timedif * (-1);
/* only change, if the time delta is within the parameter range */
if(timedif <= chksec)
{
if(stime(&caltime))
{
if(errno == EPERM)
fprintf(stderr, "You must be super user to set time\n");
else
fprintf(stderr, "stime() function error is %d\n", errno);
}
}
else
fprintf(stderr, "change ignored! range parameter is over %d hours\n", chkno);
exit(0);
}
/*
* this function terminates the utility if the datagram doesn't
* return in the alloted time
*/
int timedout()
{
fprintf(stderr, "setime timed out.\n");
exit (1);
}
/*
* this function takes a month string, converts it to lowercase and
* returns an integer corresponding to the number of the month or zero
* for an error
*/
int retmonth(mstr)
char *mstr;
{
int i;
for(i=0; i < strlen(mstr); i++) /*month string to lowercase*/
mstr[i] = to_lowercase(mstr[i]);
if(strcmp(mstr,"jan") == 0)
return 1;
if(strcmp(mstr,"feb") == 0)
return 2;
if(strcmp(mstr,"mar") == 0)
return 3;
if(strcmp(mstr,"apr") == 0)
return 4;
if(strcmp(mstr,"may") == 0)
return 5;
if(strcmp(mstr,"jun") == 0)
return 6;
if(strcmp(mstr,"jul") == 0)
return 7;
if(strcmp(mstr,"aug") == 0)
return 8;
if(strcmp(mstr,"sep") == 0)
return 9;
if(strcmp(mstr,"oct") == 0)
return 10;
if(strcmp(mstr,"nov") == 0)
return 11;
if(strcmp(mstr,"dec") == 0)
return 12;
return 0; /*error*/
}
/* End of File */
|