Cover V04, I03
Article
Listing 1

may95.tar


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 */