/* 

        Copyright (C) 1995,96,97
        Free Software Foundation, Inc.

   This file is part of GNU cfengine - written and maintained 
   by Mark Burgess, Dept of Computing and Engineering, Oslo College,
   Dept. of Theoretical physics, University of Oslo
 
   This program is free software; you can redistribute it and/or modify it
   under the terms of the GNU General Public License as published by the
   Free Software Foundation; either version 2, or (at your option) any
   later version.
 
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
 
  You should have received a copy of the GNU General Public License
  along with this program; if not, write to the Free Software
  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA

*/

/*******************************************************************/
/*                                                                 */
/*  Cfengine : remote client example                               */
/*                                                                 */
/*  Mark Burgess 1997                                              */
/*                                                                 */
/*******************************************************************/

#define INET 1

#include "cf.defs.h"
#include "cf.extern.h"

struct Item *VCFRUNCLASSES = NULL;
struct Item *VCFRUNHOSTLIST = NULL;

char *VCFRUNHOSTS = "cfrun.hosts";

char CFRUNOPTIONS[bufsize];

/*******************************************************************/
/* Level 0 : Main                                                  */
/*******************************************************************/

main (argc,argv)

int argc;
char **argv;

{ struct Item *ip;

CheckOptsAndInit(argc,argv);

for (ip = VCFRUNHOSTLIST; ip != NULL; ip=ip->next)
   {
   ConnectToServer(ip->name,ip->classes);
   }
}

/********************************************************************/
/* Level 1                                                          */
/********************************************************************/

CheckOptsAndInit(argc,argv)

int argc;
char **argv;

{ char buffer[maxvarsize], options[bufsize], line[bufsize], filename[bufsize], *sp;
  struct Item *ip;
  FILE *fp;
  char ch;
  int i;

/* Read hosts file */

if ((sp=getenv(CFINPUTSVAR)) != NULL)
   {
   strcpy(filename,sp);
   if (filename[strlen(filename)-1] != '/')
      {
      strcat(filename,"/");
      }
   }

strcat(filename,VCFRUNHOSTS);

if ((fp = fopen(filename,"r")) == NULL)      /* Open root file */
   {
   printf("Unable to open %s\n",filename);
   return;
   }

while (!feof(fp))
   {
   bzero(buffer,maxvarsize);
   bzero(options,bufsize);
   bzero(line,bufsize);

   fgets(line,bufsize,fp);

   if (strncmp(line,"domain",6) == 0)
      {
      sscanf(line,"domain = %[^# \n]",VDOMAIN);
      Verbose("Domain name = %s\n",VDOMAIN);
      continue;
      }

   sscanf(line,"%s %[^#\n]",buffer,options);

   if (buffer[0] == '#')
      {
      do
	 {
	 ch = getc(fp);
	 }
      while(ch != '\n');
      continue;
      }

   if (strlen(buffer) == 0)
      {
      continue;
      }

   if (!strstr(buffer,"."))
      {
      strcat(buffer,".");
      strcat(buffer,VDOMAIN);
      }
      
   if (!IsItemIn(VCFRUNHOSTLIST,buffer))
       {
       AppendItem(&VCFRUNHOSTLIST,buffer,options);
       }
   }

for (ip = VCFRUNHOSTLIST; ip != NULL; ip=ip->next)
   {
   Debug("host item: %s (%s)\n",ip->name,ip->classes);
   }

fclose(fp);

bzero(CFRUNOPTIONS,bufsize);

/* Separate command args into options and classes */

for (i = 1; i < argc; i++)
   {
   if (*argv[i] == '-')
      {
      if (strncmp(argv[i],"-d",2) == 0)
	 {
	 DEBUG = true;
	 VERBOSE = true;
	 }
      else if (strncmp(argv[i],"-v",2) == 0)
	 {
	 VERBOSE=true;
         strcat(CFRUNOPTIONS,argv[i]);
         strcat(CFRUNOPTIONS," ");	 
	 }
      else if (strncmp(argv[i],"-S",2) == 0)
	 {
	 SILENT = true;
         strcat(CFRUNOPTIONS,argv[i]);
         strcat(CFRUNOPTIONS," ");	 
	 }
      else
	 {
         strcat(CFRUNOPTIONS,argv[i]);
         strcat(CFRUNOPTIONS," ");
	 }
      }
   else
      {
      AppendItem(&VCFRUNCLASSES,argv[i],"");
      }
   }

Debug("CFRUNOPTIONS string: %s\n",CFRUNOPTIONS);

for (ip = VCFRUNCLASSES; ip != NULL; ip=ip->next)
   {
   Debug("Class item: %s\n",ip->name);
   }

if (uname(&VSYSNAME) == -1)
   {
   perror("uname ");
   FatalError("cfrun: uname couldn't get kernel name info!!\n");
   }

sprintf(VFQNAME,"%s.%s",VSYSNAME.nodename,VDOMAIN);
}

/********************************************************************/

ConnectToServer(host,options)

char *host, *options;

{ struct hostent *hp;
  struct sockaddr_in cin, local;
  char sendbuffer[bufsize];
  char recvbuffer[bufsize];
  struct servent *server;
  int sd,i,err,TimeOut(),offset,n_read, len;
  char *sp;

Verbose("Connecting to server %s with options %s %s\n",host,options,CFRUNOPTIONS);

if ((hp = gethostbyname(host)) == NULL)
   {
   perror("gethostbyname: ");
   exit(1);
   }

if ((server = getservbyname(CFENGINE_SERVICE,"tcp")) == NULL)
   {
   perror("getservbyname");
   exit (1);
   }

bzero(&cin,sizeof(cin));

cin.sin_port = (unsigned int) server->s_port; /* htons((unsigned short)(server->s_port)); */
cin.sin_addr.s_addr = ((struct in_addr *)(hp->h_addr))->s_addr;
cin.sin_family = AF_INET; 

Debug("Trying to connect to %s = %s, port h=%d n=%d\n",
	host,inet_ntoa(cin.sin_addr),ntohs(server->s_port),server->s_port);

if ((sd = socket(AF_INET,SOCK_STREAM,0)) == -1)
   {
   perror("socket");
   exit(1);
   }

signal(SIGALRM,(void *)TimeOut);
alarm(CF_TIMEOUT);

if (err=connect(sd,(void *) &cin,sizeof(cin)) == -1)
   {
   printf("Host %s didn't answer poll\n",host);
   return;
   }

alarm(0);
signal(SIGALRM,SIG_DFL);

len = sizeof(struct sockaddr_in);

if (getsockname(sd,(struct sockaddr *)&local,&len) == -1)
   {
   printf("cfd: couldn't get socket address\n");
   perror("getsockname");
   return false;
   }

Verbose("Identifying as %s as %s\n",inet_ntoa(local.sin_addr),VFQNAME);

if (! IdentifyForVerification(sd,inet_ntoa(local.sin_addr),VFQNAME))
   {
   printf("cfengine: server registration procedure failed");
   errno = EPERM;
   return;
   }


sprintf(sendbuffer,"EXEC %s %s",options,CFRUNOPTIONS);

if (send(sd,sendbuffer,bufsize,0) == -1)
   {
   perror("send");
   close(sd);
   return;
   }

SendClassData(sd,sendbuffer);

Verbose("========================================================================\n");
Verbose("%s replies..\n",host);
Verbose("========================================================================\n");

while (true)
   {
   bzero(recvbuffer,bufsize);

   if ((n_read = recv(sd, recvbuffer, bufsize,0)) == -1)
      {
      if (errno == EINTR) 
         {
         continue;
         }

      close(sd);
      return;
      }

   if ((strcmp(recvbuffer,CFD_TERMINATOR) == 0) || (strcmp(recvbuffer,"") == 0))
      {
      break;
      }

   if (strstr(recvbuffer,"cfd:")) /* Don't print messages fom cfd unless -v */
      {
      Verbose("%s\n",recvbuffer);
      continue;
      }

   printf("%s\n",recvbuffer);
   }

Verbose("========================================================================\n");

close(sd);
}


/********************************************************************/
/* Level 2                                                          */
/********************************************************************/

SendClassData(sd, sendbuffer)

int sd;
char *sendbuffer;

{ struct Item *ip;
  int used;
  char *sp;

sp = sendbuffer;
used = 0;
bzero(sendbuffer,bufsize);
  
for (ip = VCFRUNCLASSES; ip != NULL; ip = ip->next)
   {
   if (used + strlen(ip->name) +2 > bufsize)
      {
      if (send(sd,sendbuffer,bufsize,0) == -1)
         {
         perror("send");
         return;
         }

      used = 0;
      sp = sendbuffer;
      bzero(sendbuffer,bufsize);
      }
   
   strcat(sendbuffer,ip->name);
   strcat(sendbuffer," ");

   sp += strlen(ip->name)+1;
   used += strlen(ip->name)+1;
   }

if (used + strlen(CFD_TERMINATOR) +2 > bufsize)
   {
   if (send(sd,sendbuffer,bufsize,0) == -1)
      {
      perror("send");
      return;
      }

   used = 0;
   sp = sendbuffer;
   bzero(sendbuffer,bufsize);
   }
   
sprintf(sp,CFD_TERMINATOR);

if (send(sd,sendbuffer,bufsize,0) == -1)
   {
   perror("send");
   return;
   }
}


/* EOF */

RotateFiles(){}
IsWildItemIn(){}
