/* cfengine for GNU
 
        Copyright (C) 1995
        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

*/
 

/*********************************************************************/
/*                                                                   */
/*  TOOLKITS: "sharable" library                                     */
/*                                                                   */
/*********************************************************************/

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

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

IsAbsoluteFileName(f)

char *f;

{
if (*f == '/' || *f == '.')
   {
   return true;
   }

return false;
}

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

AddSlash(str)

char *str;

{
if (str[strlen(str)-1] != '/')
   {
   strcat(str,"/");
   }
}

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

DeleteSlash(str)

char *str;

{
if (str[strlen(str)-1] == '/')
   {
   str[strlen(str)-1] = '\0';
   }
}

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

ChopLastNode(str)

  /* Chop off trailing node name (possible blank) starting from
     last character and removing up to the first / encountered 
     e.g. /a/b/c -> /a/b
          /a/b/ -> /a/b                                        */

char *str;

{ char *sp;
  int hasslash = false;

for (sp = str; *sp != '\0'; sp++)
   {
   if (*sp == '/')
      {
      hasslash = true;
      break;
      }
   }

if ( ! hasslash)
   {
   return false;
   }

for (sp = str+strlen(str); *sp != '/'; sp--)        /* skip link name */
   {
   *sp = '\0';
   }

*sp = '\0';
return true;
}

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

char *CanonifyName(str)

char *str;

{ static char buffer[bufsize];
  char *sp;

bzero(buffer,bufsize);
strcpy(buffer,str);

for (sp = buffer; *sp != '\0'; sp++)
    {
    if (!isalnum(*sp))
       {
       *sp = '_';
       }
    }

return buffer;
}

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

char *ASUniqueName(str) /* generates a unique action sequence name */

char *str;

{ static char buffer[bufsize];
  struct Item *ip;
  char *sp;

bzero(buffer,bufsize);
strcpy(buffer,str);

for (ip = VADDCLASSES; ip != NULL; ip=ip->next)
   {
   if (strlen(buffer)+strlen(ip->name)+3 > maxlinksize)
      {
      break;
      }
   
   strcat(buffer,".");
   strcat(buffer,ip->name);
   }

return buffer;
}

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

char *ReadLastNode(str)

  /* Chop off trailing node name (possible blank) starting from
     last character and removing up to the first / encountered 
     e.g. /a/b/c -> /a/b
          /a/b/ -> /a/b                                        */

char *str;

{ char *sp;

for (sp = str+strlen(str); *sp != '/'; sp--)        /* skip link name */
   {
   }

return sp+1;
}

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

MakeDirectoriesFor(file)  /* Make all directories which underpin file */

char *file;

{ char *sp,*spc;
  char currentpath[bufsize];
  char pathbuf[bufsize];
  struct stat statbuf;

strcpy(pathbuf,file);                                        /* local copy */

for (sp = pathbuf+strlen(file); *sp != '/'; sp--)        /* skip link name */
   {
   *sp = '\0';
   }

if (lstat(pathbuf,&statbuf) != -1)
   {
   if (VERBOSE || DEBUG || D2)
      {
      if (S_ISLNK(statbuf.st_mode))
         {
         printf("cfengine:%s: INFO: %s is a symbolic link, not a true directory!\n",VPREFIX,pathbuf);
         }
      }

   if (! S_ISLNK(statbuf.st_mode) && ! S_ISDIR(statbuf.st_mode))
      {
      printf("cfengine:%s: Warning. The object %s is not a directory.\n",VPREFIX,pathbuf);
      printf("cfengine:%s: Cannot make a new directory without deleting it!\n\n",VPREFIX);
      return(false);
      }
   }

for (sp = file, spc = currentpath; *sp != '\0'; sp++)
   {
   if (*sp != '/' && *sp != '\0')
      {
      *spc = *sp;
      spc++;
      }
   else
      {
      *spc = '\0';

      if (strlen(currentpath) == 0)
         {
         }
      else if (stat(currentpath,&statbuf) == -1)
         {
         Debug2("cfengine: Making directory %s, mode %o\n",currentpath,DEFAULTMODE);

         if (! DONTDO)
            {
            if (mkdir(currentpath,DEFAULTMODE) == -1)
               {
               printf("cfengine:%s: Unable to make path %s\n",VPREFIX,file);
               perror("          ");
               return(false);
               }
            }
         }
      else
         {
         if (! S_ISDIR(statbuf.st_mode))
            {
            printf("cfengine:%s: cannot make %s. %s is not a directory!\n",VPREFIX,file,currentpath);
            return(false);
            }
         }

      *spc = '/';
      spc++;
      }
   }

Debug("Directory for %s exists. Okay\n",file);
return(true);
}

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

BufferOverflow(str1,str2)                   /* Should be an inline ! */

char *str1, *str2;

{ int len = strlen(str2);

if ((strlen(str1)+len) > (bufsize - buffer_margin))
   {
   printf("cfengine:%s: Buffer overflow constructing string. Increase bufsize macro.\n",VPREFIX);
   printf("cfengine:%s: tried to add %s to %s\n",VPREFIX,str2,str1);
   return true;
   }

return false;
}

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

Chop(str)

char *str;

{
if (str == NULL)
   {
   return;
   }

str[strlen(str)-1] = '\0';
}


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

Banner(string)

char *string;

{
Verbose("---------------------------------------------------------------------\n");
Verbose("%s\n",string);
Verbose("---------------------------------------------------------------------\n\n");
}

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

SensibleFile(nodename,path)

char *nodename, *path;

{ int i, suspicous = true;
  char *sp;

for (i = 0; VSKIPFILES[i] != NULL; i++)
   {
   if (strcmp(nodename,VSKIPFILES[i]) == 0)
      {
      return false;
      }
   }

for (sp = nodename; *sp != '\0'; sp++) /* Check for files like ".. ." */
   {
   if ((*sp != '.') && ! isspace(*sp))
      {
      suspicous = false;
      return true;
      }
   }

Silent("cfengine:%s: Suspicous looking file object \"%s\" masquerading as hidden file in %s\n",VPREFIX,nodename,path);

return true;
}

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

IgnoredOrExcluded(file,inclusions,exclusions)

char *file;
struct Item *inclusions, *exclusions;

{ char linkbuf[bufsize], *lastnode;

if (strstr(file,"/"))
   {
   for (lastnode = file+strlen(file); *lastnode != '/'; lastnode--)
      {
      }

   lastnode++;
   }
else
   {
   lastnode = file;
   }

if (inclusions != NULL && !IsWildItemIn(inclusions,lastnode))
   {
   Verbose("cfengine: skipping non-included pattern %s\n",file);
   return true;
   }

if (IsWildItemIn(VEXCLUDECOPY,lastnode) || IsWildItemIn(exclusions,lastnode))
   {
   Verbose("cfengine: skipping excluded pattern %s\n",file);
   return true;
   }

return false;
}


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


TimeOut()

{
alarm(0);
Verbose("cfengine: Time out\n");
}

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

RecvSocketStream(sd,buffer,toget,nothing)

int sd,toget,nothing;
char *buffer;

{ int already, got;

for (already = 0; already != toget; already += got)
   {
   got = recv(sd,buffer+already,toget-already,0);

   if ((got == -1) || (got == 0))
      {
      return -1;
      }

   Debug("    (Concatenated %d from stream)\n",got);
   }

return toget;
}

/*********************************************************************/
/* TOOLKIT : Error                                                   */
/*********************************************************************/

FatalError(s)

char *s;

{
fprintf (stderr,"cfengine:%s:%s:%s\n",VPREFIX,VCURRENTFILE,s);
ReleaseCurrentLock(CFSTARTTIME);
exit(1);
}

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

Warning(s)

char *s;

{
if (WARNINGS)
   { 
   fprintf (stderr,"cfengine:%s:%s:%d: Warning: %s\n",VPREFIX,VCURRENTFILE,LINENUMBER,s);
   }
}

/*********************************************************************/
/* TOOLKIT : String                                                  */
/*********************************************************************/

char ToLower (ch)

char ch;

{
if (isdigit(ch) || ispunct(ch))
   {
   return(ch);
   }

if (islower(ch))
   {
   return(ch);
   }
else
   {
   return(ch - 'A' + 'a');
   }
}


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

char ToUpper (ch)

char ch;

{
if (isdigit(ch) || ispunct(ch))
   {
   return(ch);
   }

if (isupper(ch))
   {
   return(ch);
   }
else
   {
   return(ch - 'a' + 'A');
   }
}
