Attached are patches for various bugs and new features to cfengine.  All 
patches are against cfengine 3.0.2.


[FIX] patch-bsd-df

space returned from statfs() is in number of blocks, which is not 
necessarily 1024 bytes.



[FEATURE] patch-collapse-level

Extend collapse_destination_dir constraint to allow collapsing of up to an 
arbitrary number of directory levels.  This is useful if you have organized 
files into sets by putting them into different source directories, such as 
in the example below:

  body copy_from copy_c1($srcdir) {
    source => "$(srcdir");
    collapse_destination_dir => 1;
  }

  bundle agent docopy($src, $dst) {
    vars:
        "dirs" slist => { "$(src)/$(sys.os)",
                          "$(src)/$(sys.os)-$(sys.arch)",
                          "$(src)/$(sys.os)-$(sys.release)",
                          "$(src)/$(sys.os)-$(sys.release)-$(sys.arch)",
                          "$(src)/.*/.*" };
    files:
        "$dst"
                copy_from => copy_c1("$(src)"),
                depth_search => recurse_pkg_includedirs("inf", "@(dirs)");
  }



[FEATURE] patch-diskfree

adds diskfree(dir) function to return space available at any location.



[FEATURE] patch-dz-arithmetic

adds simple arithmetic functions



[FIX] patch-exclude-first

Fixes the bug where only include_dirs is considered when both include_dirs 
and exclude_dirs are specified in a search, by evaluating the exclusion 
list first.



[FIX] patch-linkstatus

Fixes the problem where various link promises are always counted as 
repaired.



[FIX] patch-method-nochg

Fixes the problem where usemethod invocations are counted as extra repaired 
promises.



[FIX] patch-moveobstructions-whennofile

Whether or not a directory is moved aside in file operations should not 
depend on the when_no_source attribute.



[FEATURE/FIX] patch-netgroup

Allow various server controls to match based on netgroup in addition to IP 
or hostname.  Specify "@netgroup-name" in place of hostnames to do netgroup 
matching.
This patch also fixes the lack of hostname based matching on the 
trustkeysfrom and dynamicaddresses promises.



[FIX] patch-nodeleteslash

When verifying soft links, do not attempt to delete the trailing slash from 
the current on-disk state if the expected link destination also has a 
trailing slash.



[FIX] patch-nodupclass

Avoid adding duplicate result classes to the global class list.  This 
prevents /var/cfengine/state/allclasses.txt from exploding in size when you 
have lots of result classes.



[FIX] patch-regex-detect

Improve regex detection in IsRegex() to decrease the chance of false 
positives.



[FIX] patch-single-copy

The files_single_copy list was only being matched quazi-literally, where 
the file name was actually being used as a regex and the single copy list 
was being matched against that.


--- src/storage_tools.c~        2009-08-24 21:37:25.000000000 -0400
+++ src/storage_tools.c 2009-08-24 21:38:53.000000000 -0400
@@ -100,9 +100,9 @@
 #endif
 
 #if defined NETBSD || defined FREEBSD || defined OPENBSD || defined SUNOS || 
defined HPuUX || defined DARWIN
-    total = buf.f_blocks;
-    used = buf.f_blocks - buf.f_bfree;
-    avail = buf.f_bavail;
+    total = buf.f_blocks * buf.f_bsize / blocksize;
+    used = (buf.f_blocks - buf.f_bfree)  * buf.f_bsize / blocksize;
+    avail = buf.f_bavail * buf.f_bsize / blocksize;
 #endif
 
 #if defined OSF
diff -u src~/attributes.c src/attributes.c
--- src~/attributes.c   2009-08-25 20:40:55.000000000 -0400
+++ src/attributes.c    2009-08-25 21:14:00.000000000 -0400
@@ -733,7 +733,13 @@
    }
        
 f.stealth = GetBooleanConstraint("stealth",pp->conlist);
-f.collapse = GetBooleanConstraint("collapse_destination_dir",pp->conlist);
+
+value = (char 
*)GetConstraint("collapse_destination_dir",pp->conlist,CF_SCALAR);
+if (value == NULL)
+   f.collapse = 0;
+else
+   f.collapse = String2CollapseLevel(value);
+
 f.preserve = GetBooleanConstraint("preserve",pp->conlist);
 f.type_check = GetBooleanConstraint("type_check",pp->conlist);
 f.force_update = GetBooleanConstraint("force_update",pp->conlist);
diff -u src~/conversion.c src/conversion.c
--- src~/conversion.c   2009-08-25 20:40:55.000000000 -0400
+++ src/conversion.c    2009-08-25 21:20:42.000000000 -0400
@@ -237,6 +237,29 @@
 
 /****************************************************************************/
 
+int String2CollapseLevel(char *s)
+
+{ int i;
+  static char *infs[] = {"true", "yes", "on", "inf", NULL};
+  static char *zeros[] = {"false", "no", "off", NULL};
+
+if (!s) return 0;
+for (i = 0; infs[i] != NULL; i++)
+   {
+   if (strcmp(s,infs[i]) == 0)
+      return CF_INFINITY;
+   }
+for (i = 0; zeros[i] != NULL; i++)
+   {
+   if (strcmp(s,zeros[i]) == 0)
+      return 0;
+   }
+
+return (int)Str2Int(s);
+}
+
+/****************************************************************************/
+
 enum cfcomparison String2Comparison(char *s)
 
 { int i;
diff -u src~/files_copy.c src/files_copy.c
--- src~/files_copy.c   2009-08-25 20:40:55.000000000 -0400
+++ src/files_copy.c    2009-08-25 20:59:45.000000000 -0400
@@ -80,7 +80,7 @@
 
    CfOut(cf_verbose,""," ->>  Entering %s\n",source);
    SetSearchDevice(&ssb,pp);
-   SourceSearchAndCopy(source,destination,attr.recursion.depth,attr,pp);
+   SourceSearchAndCopy(source,destination,attr.recursion.depth,0,attr,pp);
    
    if (stat(destination,&dsb) != -1)
       {
diff -u src~/files_interfaces.c src/files_interfaces.c
--- src~/files_interfaces.c     2009-08-25 20:40:55.000000000 -0400
+++ src/files_interfaces.c      2009-08-25 21:07:30.000000000 -0400
@@ -36,7 +36,7 @@
 
 /* File copying is a special case, particularly complex - cannot be integrated 
*/
 
-void SourceSearchAndCopy(char *from,char *to,int maxrecurse,struct Attributes 
attr,struct Promise *pp)
+void SourceSearchAndCopy(char *from,char *to,int maxrecurse,int level,struct 
Attributes attr,struct Promise *pp)
 
 { struct stat sb, dsb;
   char newfrom[CF_BUFSIZE];
@@ -124,7 +124,7 @@
 
    /* If we are tracking subdirs in copy, then join else don't add*/
 
-   if (attr.copy.collapse)
+   if (level < attr.copy.collapse)
       {
       if (!S_ISDIR(sb.st_mode) && !JoinPath(newto,dirp->d_name))
          {
@@ -164,7 +164,7 @@
 
       /* Only copy dirs if we are tracking subdirs */
 
-      if (!attr.copy.collapse && (stat(newto,&dsb) == -1))
+      if (!(level < attr.copy.collapse) && (stat(newto,&dsb) == -1))
          {
          if (mkdir(newto,0700) == -1)
             {
@@ -181,12 +181,12 @@
 
       CfOut(cf_verbose,""," ->>  Entering %s\n",newto);
 
-      if (!attr.copy.collapse)
+      if (!(level < attr.copy.collapse))
          {
          VerifyCopiedFileAttributes(newto,&dsb,&sb,attr,pp);
          }
       
-      SourceSearchAndCopy(newfrom,newto,maxrecurse-1,attr,pp);
+      SourceSearchAndCopy(newfrom,newto,maxrecurse-1,level+1,attr,pp);
       }
    else
       {
diff -u src~/mod_files.c src/mod_files.c
--- src~/mod_files.c    2009-08-25 20:40:55.000000000 -0400
+++ src/mod_files.c     2009-08-25 21:11:16.000000000 -0400
@@ -303,7 +303,7 @@
    {
    {"source",cf_str,CF_PATHRANGE,"Reference source file from which to copy"},
    {"servers",cf_slist,"[A-Za-z0-9_.:-]+","List of servers in order of 
preference from which to copy"},
-   {"collapse_destination_dir",cf_opts,CF_BOOL,"true/false Place files in 
subdirectories into the root destination directory during copy"},
+   
{"collapse_destination_dir",cf_str,"0|true|false|yes|no|on|off|[0-9][0-9]*|inf","Place
 files in subdirectories into the root destination directory during copy, up to 
the specified number of levels"},
    {"compare",cf_opts,"atime,mtime,ctime,digest,hash","Menu option policy for 
comparing source and image file attributes"},
    {"copy_backup",cf_opts,"true,false,timestamp","Menu option policy for file 
backup/version control"},
    {"encrypt",cf_opts,CF_BOOL,"true/false use encrypted data stream to connect 
to remote host"},
diff -u src~/prototypes3.h src/prototypes3.h
--- src~/prototypes3.h  2009-08-25 20:40:55.000000000 -0400
+++ src/prototypes3.h   2009-08-25 21:20:55.000000000 -0400
@@ -231,6 +231,7 @@
 int Signal2Int(char *s);
 enum cfreport String2ReportLevel(char *typestr);
 enum cfhashes String2HashType(char *typestr);
+int String2CollapseLevel(char *s);
 enum cfcomparison String2Comparison(char *s);
 enum cflinktype String2LinkType(char *s);
 enum cfdatatype Typename2Datatype(char *name);
@@ -550,7 +551,7 @@
 
 /* files_interfaces.c */
 
-void SourceSearchAndCopy(char *from,char *to,int maxrecurse,struct Attributes 
attr,struct Promise *pp);
+void SourceSearchAndCopy(char *from,char *to,int maxrecurse,int level,struct 
Attributes attr,struct Promise *pp);
 void VerifyCopy(char *source,char *destination,struct Attributes attr,struct 
Promise *pp);
 void PurgeLocalFiles(struct Item *filelist,char *directory,struct Attributes 
attr,struct Promise *pp);
 void CopyFile(char *sourcefile,char *destfile,struct stat sourcestatbuf,struct 
Attributes attr, struct Promise *pp);
Only in src~: .mod_common.c.swp
diff -u src~/cf3.defs.h src/cf3.defs.h
--- src~/cf3.defs.h     2009-08-24 21:12:52.000000000 -0400
+++ src/cf3.defs.h      2009-08-24 21:13:55.000000000 -0400
@@ -488,6 +488,7 @@
    cfn_changedbefore,
    cfn_classify,
    cfn_classmatch,
+   cfn_diskfree,
    cfn_execresult,
    cfn_fileexists,
    cfn_filesexist,
diff -u src~/evalfunction.c src/evalfunction.c
--- src~/evalfunction.c 2009-08-24 21:12:52.000000000 -0400
+++ src/evalfunction.c  2009-08-24 21:42:52.000000000 -0400
@@ -3898,6 +3898,45 @@
 return rval;
 }
 
+/*********************************************************************/
+
+struct Rval FnCallDiskFree(struct FnCall *fp,struct Rlist *finalargs)
+
+{ static char *argtemplate[] =
+     {
+     CF_ANYSTRING,
+     NULL
+     };
+  static enum cfdatatype argtypes[] =
+      {
+      cf_str,
+      cf_notype
+      };
+  
+  struct Rlist *rp;
+  struct Rval rval;
+  char buffer[CF_BUFSIZE];
+  u_long df;
+  
+buffer[0] = '\0';  
+ArgTemplate(fp,argtemplate,argtypes,finalargs); /* Arg validation */
+
+df = GetDiskUsage((char *)finalargs->item, cfabs);
+if (df == CF_INFINITY) df = 0;
+snprintf(buffer,CF_BUFSIZE-1,"%d", df);
+
+if ((rval.item = strdup(buffer)) == NULL)
+   {
+   FatalError("Memory allocation in FnCallGetGid");
+   }
+
+/* end fn specific content */
+
+rval.rtype = CF_SCALAR;
+return rval;
+}
+
+
 
 /*********************************************************************/
 /* Level                                                             */
diff -u src~/fncall.c src/fncall.c
--- src~/fncall.c       2009-08-24 21:12:52.000000000 -0400
+++ src/fncall.c        2009-08-24 21:16:16.000000000 -0400
@@ -444,6 +444,9 @@
    case cfn_selectservers:
        rval = FnCallSelectServers(fp,expargs);
        break;
+   case cfn_diskfree:
+       rval = FnCallDiskFree(fp,expargs);
+       break;
        
    case cfn_unknown:
        CfOut(cf_error,"","Un-registered function call");
diff -u src~/mod_common.c src/mod_common.c
--- src~/mod_common.c   2009-08-24 21:12:52.000000000 -0400
+++ src/mod_common.c    2009-08-24 21:13:47.000000000 -0400
@@ -52,6 +52,7 @@
    {"changedbefore",cf_class,2,"True if arg1 was changed before arg2 (ctime)"},
    {"classify",cf_class,1,"True if the canonicalization of the argument is a 
currently defined class"},
    {"classmatch",cf_class,1,"True if the regular expression matches any 
currently defined class"},
+   {"diskfree",cf_int,1,"Return the free space (in KB) available for a 
directory (0 if not found)"},
    {"execresult",cf_str,2,"Execute named command and assign output to 
variable"},
    {"fileexists",cf_class,1,"True if the named file can be accessed"},
    {"filesexist",cf_class,1,"True if the named list of files can ALL be 
accessed"},
diff -u src~/prototypes3.h src/prototypes3.h
--- src~/prototypes3.h  2009-08-24 21:12:52.000000000 -0400
+++ src/prototypes3.h   2009-08-24 21:16:06.000000000 -0400
@@ -437,6 +437,7 @@
 struct Rval FnCallRegistryValue(struct FnCall *fp,struct Rlist *finalargs);
 struct Rval FnCallLastNode(struct FnCall *fp,struct Rlist *finalargs);
 struct Rval FnCallFileSexist(struct FnCall *fp,struct Rlist *finalargs);
+struct Rval FnCallDiskFree(struct FnCall *fp,struct Rlist *finalargs);
 
 void *CfReadFile(char *filename,int maxsize);
 char *StripPatterns(char *file_buffer,char *pattern);
diff -ur src~/cf3.defs.h src/cf3.defs.h
--- src~/cf3.defs.h     2009-08-24 22:04:43.000000000 -0400
+++ src/cf3.defs.h      2009-08-24 22:06:51.000000000 -0400
@@ -483,12 +483,14 @@
    {
    cfn_accessedbefore,
    cfn_accum,
+   cfn_add,
    cfn_ago,
    cfn_canonify,
    cfn_changedbefore,
    cfn_classify,
    cfn_classmatch,
    cfn_diskfree,
+   cfn_divide,
    cfn_execresult,
    cfn_fileexists,
    cfn_filesexist,
@@ -513,6 +515,7 @@
    cfn_ldaparray,
    cfn_ldaplist,
    cfn_ldapvalue,
+   cfn_multiply,
    cfn_now,
    cfn_date,
    cfn_peers,
@@ -540,6 +543,7 @@
    cfn_splayclass,
    cfn_splitstring,
    cfn_strcmp,
+   cfn_subtract,
    cfn_usemodule,
    cfn_userexists,
    cfn_unknown,
diff -ur src~/fncall.c src/fncall.c
--- src~/fncall.c       2009-08-24 22:04:43.000000000 -0400
+++ src/fncall.c        2009-08-24 22:15:14.000000000 -0400
@@ -447,6 +447,18 @@
    case cfn_diskfree:
        rval = FnCallDiskFree(fp,expargs);
        break;
+   case cfn_add:
+       rval = FnCallArithmetic(fp,expargs,'+');
+       break;
+   case cfn_subtract:
+       rval = FnCallArithmetic(fp,expargs,'-');
+       break;
+   case cfn_multiply:
+       rval = FnCallArithmetic(fp,expargs,'*');
+       break;
+   case cfn_divide:
+       rval = FnCallArithmetic(fp,expargs,'/');
+       break;
        
    case cfn_unknown:
        CfOut(cf_error,"","Un-registered function call");
diff -ur src~/mod_common.c src/mod_common.c
--- src~/mod_common.c   2009-08-24 22:04:43.000000000 -0400
+++ src/mod_common.c    2009-08-24 22:17:25.000000000 -0400
@@ -47,12 +47,14 @@
    {
    {"accessedbefore",cf_class,2,"True if arg1 was accessed before arg2 
(atime)"},
    {"accumulated",cf_int,6,"Convert an accumulated amount of time into a 
system representation"},
+   {"add",cf_int,2,"Add two integers"},
    {"ago",cf_int,6,"Convert a time relative to now to an integer system 
representation"},
    {"canonify",cf_str,1,"Convert an abitrary string into a legal class name"},
    {"changedbefore",cf_class,2,"True if arg1 was changed before arg2 (ctime)"},
    {"classify",cf_class,1,"True if the canonicalization of the argument is a 
currently defined class"},
    {"classmatch",cf_class,1,"True if the regular expression matches any 
currently defined class"},
    {"diskfree",cf_int,1,"Return the free space (in KB) available for a 
directory (0 if not found)"},
+   {"divide",cf_int,2,"Divide two integers"},
    {"execresult",cf_str,2,"Execute named command and assign output to 
variable"},
    {"fileexists",cf_class,1,"True if the named file can be accessed"},
    {"filesexist",cf_class,1,"True if the named list of files can ALL be 
accessed"},
@@ -77,6 +79,7 @@
    {"ldaparray",cf_class,6,"Extract all values from an ldap record"},
    {"ldaplist",cf_slist,6,"Extract all named values from multiple ldap 
records"},
    {"ldapvalue",cf_str,6,"Extract the first matching named value from ldap"},
+   {"multiply",cf_int,2,"Multiply two integers"},
    {"now",cf_int,0,"Convert the current time into system representation"},
    {"on",cf_int,6,"Convert an exact date/time to an integer system 
representation"},
    {"peers",cf_slist,3,"Get a list of peers (not including ourself) from the 
partition to which we belong"},
@@ -104,6 +107,7 @@
    {"splayclass",cf_class,2,"True if the first argument's time-slot has 
arrived, according to a policy in arg2"},
    {"splitstring",cf_slist,3,"Convert a string in arg1 into a list of max arg3 
strings by splitting on a regular expression in arg2"},
    {"strcmp",cf_class,2,"True if the two strings match exactly"},
+   {"subtract",cf_int,2,"Subtract two integers"},
    {"usemodule",cf_class,2,"Execute cfengine module script and set class if 
successful"},
    {"userexists",cf_class,1,"True if user name or numerical id exists on this 
host"},
    {NULL,cf_notype,0,NULL}
--- src/prototypes3.h~  2009-08-24 22:22:00.000000000 -0400
+++ src/prototypes3.h   2009-08-24 22:22:16.000000000 -0400
@@ -438,6 +438,7 @@
 struct Rval FnCallLastNode(struct FnCall *fp,struct Rlist *finalargs);
 struct Rval FnCallFileSexist(struct FnCall *fp,struct Rlist *finalargs);
 struct Rval FnCallDiskFree(struct FnCall *fp,struct Rlist *finalargs);
+struct Rval FnCallArithmetic(struct FnCall *fp,struct Rlist *finalargs,char 
ch);
 
 void *CfReadFile(char *filename,int maxsize);
 char *StripPatterns(char *file_buffer,char *pattern);
--- src/evalfunction.c~ 2009-08-24 22:25:31.000000000 -0400
+++ src/evalfunction.c  2009-08-24 22:25:55.000000000 -0400
@@ -3937,6 +3937,63 @@
 return rval;
 }
 
+/*********************************************************************/
+
+struct Rval FnCallArithmetic(struct FnCall *fp,struct Rlist *finalargs, char 
ch)
+
+{ static char *argtemplate[] =
+     {
+     CF_ANYSTRING,
+     CF_ANYSTRING,
+     NULL
+     };
+  static enum cfdatatype argtypes[] =
+      {
+      cf_str,
+      cf_str,
+      cf_notype
+      };
+ 
+  struct Rlist *rp;
+  struct Rval rval;
+  char buffer[CF_BUFSIZE];
+  int a, b;
+
+buffer[0] = '\0';
+
+ArgTemplate(fp,argtemplate,argtypes,finalargs); /* Arg validation */
+
+a = Str2Int(finalargs->item);
+b = Str2Int(finalargs->next->item);
+
+switch (ch)
+   {
+   case '+':
+       a += b;
+       break;
+   case '-':
+       a -= b;
+       break;
+   case '*':
+       a *= b;
+       break;
+   case '/':
+       if (b==0) a = 0; else a /= b;
+       break;
+   }
+
+snprintf(buffer,CF_BUFSIZE-1,"%d", a);
+
+if ((rval.item = strdup(buffer)) == NULL)
+   {
+   FatalError("Memory allocation in FnCallGetGid");
+   }
+
+/* end fn specific content */
+
+rval.rtype = CF_SCALAR;
+return rval;
+}
 
 
 /*********************************************************************/
diff -ur src~/recursion.c src/recursion.c
--- src~/recursion.c    2009-08-26 00:06:42.000000000 -0400
+++ src/recursion.c     2009-08-26 00:07:38.000000000 -0400
@@ -217,18 +217,18 @@
 {
 Debug("SkipDirLinks(%s,%s)\n",path,lastnode);
 
-if ((r.include_dirs != NULL) && !(MatchRlistItem(r.include_dirs,path) || 
MatchRlistItem(r.include_dirs,lastnode)))
-   {
-   CfOut(cf_verbose,"","Skipping matched non-included directory %s\n",path);
-   return true;
-   }
-
 if (MatchRlistItem(r.exclude_dirs,path) || 
MatchRlistItem(r.exclude_dirs,lastnode))
    {
    CfOut(cf_verbose,"","Skipping matched excluded directory %s\n",path);
    return true;
    }       
 
+if ((r.include_dirs != NULL) && !(MatchRlistItem(r.include_dirs,path) || 
MatchRlistItem(r.include_dirs,lastnode)))
+   {
+   CfOut(cf_verbose,"","Skipping matched non-included directory %s\n",path);
+   return true;
+   }
+
 return false;
 }
 
diff -ur src~/files_interfaces.c src/files_interfaces.c
--- src~/files_interfaces.c     2009-08-22 08:05:02.000000000 -0400
+++ src/files_interfaces.c      2009-08-24 20:05:20.000000000 -0400
@@ -1322,7 +1322,7 @@
 void LinkCopy(char *sourcefile,char *destfile,struct stat *sb,struct 
Attributes attr, struct Promise *pp)
 
 { char linkbuf[CF_BUFSIZE],*lastnode;
-  int succeed = false;
+  int status = CF_UNKNOWN;
   struct stat dsb;
 
 /* Link the file to the source, instead of copying */
@@ -1370,20 +1370,20 @@
        
        if (*linkbuf == '.')
           {
-          succeed = VerifyRelativeLink(destfile,linkbuf,attr,pp);
+          status = VerifyRelativeLink(destfile,linkbuf,attr,pp);
           }
        else
           {
-          succeed = VerifyLink(destfile,linkbuf,attr,pp);
+          status = VerifyLink(destfile,linkbuf,attr,pp);
           }
        break;
        
    case cfa_relative:
-       succeed = VerifyRelativeLink(destfile,linkbuf,attr,pp);
+       status = VerifyRelativeLink(destfile,linkbuf,attr,pp);
        break;
        
    case cfa_absolute:
-       succeed = VerifyAbsoluteLink(destfile,linkbuf,attr,pp);
+       status = VerifyAbsoluteLink(destfile,linkbuf,attr,pp);
        break;
        
    default:
@@ -1391,7 +1391,7 @@
        return;
    }
 
-if (succeed)
+if (status == CF_CHG || status == CF_NOP)
    {
    if (lstat(destfile,&dsb) == -1)
       {
@@ -1402,7 +1402,12 @@
       VerifyCopiedFileAttributes(destfile,&dsb,sb,attr,pp);
       }
    
-   cfPS(cf_inform,CF_CHG,"",pp,attr," -> Created link %s", destfile);
+   if (status == CF_CHG)
+      cfPS(cf_inform,status,"",pp,attr," -> Created link %s", destfile);
+   else if (status == CF_NOP)
+      ; /*cfPS(cf_inform,status,"",pp,attr," -> Link %s as promised", 
destfile);*/
+   else
+      cfPS(cf_inform,status,"",pp,attr," -> Unable to create link %s", 
destfile);
    }
 }
 
diff -ur src~/files_links.c src/files_links.c
--- src~/files_links.c  2009-08-22 08:08:32.000000000 -0400
+++ src/files_links.c   2009-08-24 20:00:50.000000000 -0400
@@ -34,7 +34,7 @@
 
 /*****************************************************************************/
 
-int VerifyLink(char *destination,char *source,struct Attributes attr,struct 
Promise *pp)
+char VerifyLink(char *destination,char *source,struct Attributes attr,struct 
Promise *pp)
 
 { char to[CF_BUFSIZE],linkbuf[CF_BUFSIZE],saved[CF_BUFSIZE],absto[CF_BUFSIZE];
   int nofile = false;
@@ -84,13 +84,13 @@
 if (nofile && (attr.link.when_no_file != cfa_force) && (attr.link.when_no_file 
!= cfa_delete))
    {
    CfOut(cf_inform,"","Source %s for linking is absent",absto);
-   return false;
+   return CF_WARN;
    }
 
 if (nofile && attr.link.when_no_file == cfa_delete)
    {
    KillGhostLink(destination,attr,pp);
-   return true;
+   return CF_CHG;
    }
     
 memset(linkbuf,0,CF_BUFSIZE);
@@ -99,16 +99,16 @@
    {
    if (!MakeParentDirectory(destination,attr.move_obstructions))               
   /* link doesn't exist */
       {
-      return true;
+      return CF_FAIL;
       }
    else
       {
       if (!MoveObstruction(destination,attr,pp))
          {
-         return false;
+         return CF_FAIL;
          }
 
-      return MakeLink(destination,to,attr,pp);
+      return MakeLink(destination,to,attr,pp)?CF_CHG:CF_FAIL;
       }
    }
 else
@@ -137,34 +137,34 @@
             if (unlink(destination) == -1)
                {
                perror("unlink");
-               return true;
+               return CF_FAIL;
                }
             
-            return MakeLink(destination,to,attr,pp);
+            return MakeLink(destination,to,attr,pp)?CF_CHG:CF_FAIL;
             }
          else
             {
             CfOut(cf_error,""," !! Must remove incorrect link 
%s\n",destination);
-            return false;
+            return CF_FAIL;
             }
          }
       else
          {
          cfPS(cf_inform,CF_FAIL,"",pp,attr," !! Link %s points to %s not %s - 
not authorized to override",destination,linkbuf,to);
-         return true;
+         return CF_FAIL;
          }
       }
    else
       {
       cfPS(cf_inform,CF_NOP,"",pp,attr," -> Link %s points to %s - promise 
kept",destination,to);
-      return true;
+      return CF_NOP;
       }
    }
 }
 
 /*****************************************************************************/
 
-int VerifyAbsoluteLink(char *destination,char *source,struct Attributes 
attr,struct Promise *pp)
+char VerifyAbsoluteLink(char *destination,char *source,struct Attributes 
attr,struct Promise *pp)
 
 { char absto[CF_BUFSIZE];
   char expand[CF_BUFSIZE];
@@ -194,7 +194,7 @@
       {
       CfOut(cf_error,""," !! Failed to make absolute link in\n");
       PromiseRef(cf_error,pp);
-      return false;
+      return CF_FAIL;
       }
    else
       {
@@ -213,7 +213,7 @@
 
 /*****************************************************************************/
 
-int VerifyRelativeLink(char *destination,char *source,struct Attributes 
attr,struct Promise *pp)
+char VerifyRelativeLink(char *destination,char *source,struct Attributes 
attr,struct Promise *pp)
 
 { char *sp, *commonto, *commonfrom;
  char buff[CF_BUFSIZE],linkto[CF_BUFSIZE],add[CF_BUFSIZE];
@@ -229,7 +229,7 @@
 if (!CompressPath(linkto,source))
    {
    cfPS(cf_error,CF_INTERPT,"",pp,attr," !! Failed to link %s to 
%s\n",destination,source);
-   return false;
+   return CF_FAIL;
    }
 
 commonto = linkto;
@@ -239,7 +239,7 @@
    {
    CfOut(cf_error,""," !! Can't link file %s to itself!\n",commonto);
    PromiseRef(cf_error,pp);
-   return false;
+   return CF_FAIL;
    }
 
 while (*commonto == *commonfrom)
@@ -275,13 +275,13 @@
    
    if (!JoinPath(buff,add))
       {
-      return false;
+      return CF_FAIL;
       }
    }
 
 if (!JoinPath(buff,commonto))
    {
-   return false;
+   return CF_FAIL;
    }
  
 return VerifyLink(destination,buff,attr,pp);
@@ -289,7 +289,7 @@
 
 /*****************************************************************************/
 
-int VerifyHardLink(char *destination,char *source,struct Attributes 
attr,struct Promise *pp)
+char VerifyHardLink(char *destination,char *source,struct Attributes 
attr,struct Promise *pp)
 
 { char to[CF_BUFSIZE],linkbuf[CF_BUFSIZE],saved[CF_BUFSIZE],absto[CF_BUFSIZE];
  struct stat ssb,dsb;
@@ -319,21 +319,20 @@
 if (stat(absto,&ssb) == -1)
    {
    cfPS(cf_inform,CF_INTERPT,"",pp,attr," !! Source file %s doesn't 
exist\n",source);
-   return false;
+   return CF_WARN;
    }
 
 if (!S_ISREG(ssb.st_mode))
    {
    cfPS(cf_inform,CF_FAIL,"",pp,attr," !! Source file %s is not a regular 
file, not appropriate to hard-link\n",to);
-   return false;
+   return CF_WARN;
    }
 
 Debug2("Trying to (hard) link %s -> %s\n",destination,to);
 
 if (stat(destination,&dsb) == -1)
    {
-   MakeHardLink(destination,to,attr,pp);
-   return true;
+   return MakeHardLink(destination,to,attr,pp)?CF_CHG:CF_FAIL;
    }
 
  /* both files exist, but are they the same file? POSIX says  */
@@ -348,25 +347,24 @@
    if (dsb.st_mode == ssb.st_mode && dsb.st_size == ssb.st_size)
       {
       cfPS(cf_verbose,CF_NOP,"",pp,attr,"Hard link (%s->%s) on different 
device APPEARS okay\n",destination,to);
-      return true;
+      return CF_NOP;
       }
    }
 
 if (dsb.st_ino == ssb.st_ino && dsb.st_dev == ssb.st_dev)
    {
    cfPS(cf_verbose,CF_NOP,"",pp,attr," -> Hard link (%s->%s) exists and is 
okay\n",destination,to);
-   return true;
+   return CF_NOP;
    }
 
 CfOut(cf_inform,""," !! %s does not appear to be a hard link to 
%s\n",destination,to);
 
 if (!MoveObstruction(destination,attr,pp))
    {
-   return false;
+   return CF_FAIL;
    }
 
-MakeHardLink(destination,to,attr,pp);
-return true;
+return MakeHardLink(destination,to,attr,pp)?CF_CHG:CF_FAIL;
 }
 
 /*****************************************************************************/
diff -ur src~/prototypes3.h src/prototypes3.h
--- src~/prototypes3.h  2009-08-18 07:51:50.000000000 -0400
+++ src/prototypes3.h   2009-08-24 20:01:10.000000000 -0400
@@ -511,10 +511,10 @@
 
 /* files_links.c */
 
-int VerifyLink(char *destination,char *source,struct Attributes attr,struct 
Promise *pp);
-int VerifyAbsoluteLink(char *destination,char *source,struct Attributes 
attr,struct Promise *pp);
-int VerifyRelativeLink(char *destination,char *source,struct Attributes 
attr,struct Promise *pp);
-int VerifyHardLink(char *destination,char *source,struct Attributes 
attr,struct Promise *pp);
+char VerifyLink(char *destination,char *source,struct Attributes attr,struct 
Promise *pp);
+char VerifyAbsoluteLink(char *destination,char *source,struct Attributes 
attr,struct Promise *pp);
+char VerifyRelativeLink(char *destination,char *source,struct Attributes 
attr,struct Promise *pp);
+char VerifyHardLink(char *destination,char *source,struct Attributes 
attr,struct Promise *pp);
 int KillGhostLink(char *name,struct Attributes attr,struct Promise *pp);
 int MakeLink (char *from,char *to,struct Attributes attr,struct Promise *pp);
 int MakeHardLink (char *from,char *to,struct Attributes attr,struct Promise 
*pp);
--- src/verify_methods.c~       2009-08-24 23:30:38.000000000 -0400
+++ src/verify_methods.c        2009-08-24 23:30:50.000000000 -0400
@@ -105,7 +105,7 @@
     
    if (retval)
       {
-      cfPS(cf_verbose,CF_CHG,"",pp,a,"Method invoked successfully\n");
+      cfPS(cf_verbose,CF_REGULAR,"",pp,a,"Method invoked successfully\n");
       }
    else
       {
--- src/logging.c~      2009-08-24 23:34:09.000000000 -0400
+++ src/logging.c       2009-08-24 23:34:56.000000000 -0400
@@ -173,7 +173,6 @@
    case CF_REGULAR:
        
AddAllClasses(attr.classes.change,attr.classes.persist,attr.classes.timer);
        NotePromiseCompliance(pp,0.5);
-       PR_REPAIRED++;
        break;
        
    case CF_UNKNOWN:
--- src/files_operators.c~      2009-08-26 13:34:17.000000000 -0400
+++ src/files_operators.c       2009-08-26 13:34:29.000000000 -0400
@@ -739,7 +739,7 @@
       return true;
       }
    
-   if (S_ISDIR(sb.st_mode) && attr.link.when_no_file == cfa_force)
+   if (S_ISDIR(sb.st_mode))
       {
       cfPS(cf_verbose,CF_CHG,"",pp,attr," -> Moving directory %s to 
%s%s\n",from,from,CF_SAVED);
       
diff -ur src.orig/item-lib.c src/item-lib.c
--- src.orig/item-lib.c 2009-08-31 16:44:08.000000000 +0000
+++ src/item-lib.c      2009-08-31 17:01:53.000000000 +0000
@@ -910,6 +910,47 @@
 return(false);
 }
 
+int IsHostIn(struct Item *list,char *ip,char*username,char*hostname)
+
+/* Solve for possible regex/fuzzy models unified */
+    
+{ struct Item *ptr; 
+ 
+if ((ip == NULL) || (strlen(ip) == 0))
+   {
+   return true;
+   }
+ 
+for (ptr = list; ptr != NULL; ptr=ptr->next)
+   {
+   if (ptr->name[0] == '@' && hostname)
+      {
+      if (innetgr(ptr->name+1, hostname, username?username:"", NULL))
+         return(true);
+      }
+
+   if (FuzzySetMatch(ptr->name,ip) == 0)
+      {
+      return(true);
+      }
+
+   if (IsRegex(ptr->name))
+      {
+      if (FullTextMatch(ptr->name,ip))
+         {
+         return(true);
+         }
+
+      if (hostname && FullTextMatch(ptr->name,hostname))
+         {
+         return(true);
+         }
+      }   
+   }
+ 
+return(false);
+}
+
 /*********************************************************************/
 
 int IsFuzzyItemIn(struct Item *list,char *item)
Only in src: item-lib.c~
diff -ur src.orig/prototypes3.h src/prototypes3.h
--- src.orig/prototypes3.h      2009-08-31 16:44:08.000000000 +0000
+++ src/prototypes3.h   2009-08-31 16:58:45.000000000 +0000
@@ -774,6 +774,7 @@
 int IsItemIn (struct Item *list, char *item);
 int IsFuzzyItemIn (struct Item *list, char *item);
 int IsMatchItemIn(struct Item *list,char *item);
+int IsHostIn(struct Item *list,char *ip,char *username,char *hostname);
 int GetItemListCounter (struct Item *list, char *item);
 struct Item *ConcatLists (struct Item *list1, struct Item *list2);
 void CopyList (struct Item **dest,struct Item *source);
Only in src: prototypes3.h~
diff -ur src.orig/server.c src/server.c
--- src.orig/server.c   2009-08-31 16:44:08.000000000 +0000
+++ src/server.c        2009-08-31 17:08:29.000000000 +0000
@@ -1950,7 +1950,7 @@
          {
          Debug("Checking whether to map root privileges..\n");
          
-         if (IsMatchItemIn(ap->maproot,MapAddress(conn->ipaddr)) || 
IsRegexItemIn(ap->maproot,conn->hostname))             
+         if 
(IsHostIn(ap->maproot,MapAddress(conn->ipaddr),conn->username,conn->hostname))
             {
             conn->maproot = true;
             CfOut(cf_verbose,"","Mapping root privileges\n");
@@ -1960,7 +1960,7 @@
             CfOut(cf_verbose,"","No root privileges granted\n");
             }
          
-         if (IsMatchItemIn(ap->accesslist,MapAddress(conn->ipaddr)) || 
IsRegexItemIn(ap->accesslist,conn->hostname))
+         if 
(IsHostIn(ap->accesslist,MapAddress(conn->ipaddr),conn->username,conn->hostname))
             {
             access = true;
             Debug("Access privileges - match found\n");
@@ -1974,8 +1974,7 @@
    {
    if (strncmp(transpath,transrequest,strlen(transpath)) == 0)
       {
-      if (IsMatchItemIn(ap->accesslist,MapAddress(conn->ipaddr)) ||
-          IsRegexItemIn(ap->accesslist,conn->hostname))
+      if 
(IsHostIn(ap->accesslist,MapAddress(conn->ipaddr),conn->username,conn->hostname))
          {
          access = false;
          CfOut(cf_verbose,"","Host %s explicitly denied access to 
%s\n",conn->hostname,transrequest);
@@ -2048,7 +2047,7 @@
          {
          Debug("Checking whether to map root privileges..\n");
          
-         if (IsMatchItemIn(ap->maproot,MapAddress(conn->ipaddr)) || 
IsRegexItemIn(ap->maproot,conn->hostname))             
+         if 
(IsHostIn(ap->maproot,MapAddress(conn->ipaddr),conn->username,conn->hostname))
             {
             conn->maproot = true;
             CfOut(cf_verbose,"","Mapping root privileges\n");
@@ -2058,7 +2057,7 @@
             CfOut(cf_verbose,"","No root privileges granted\n");
             }
          
-         if (IsMatchItemIn(ap->accesslist,MapAddress(conn->ipaddr)) || 
IsRegexItemIn(ap->accesslist,conn->hostname))
+         if 
(IsHostIn(ap->accesslist,MapAddress(conn->ipaddr),conn->username,conn->hostname))
             {
             access = true;
             Debug("Access privileges - match found\n");
@@ -2072,7 +2071,7 @@
    {
    if (strcmp(ap->path,name) == 0)
       {
-      if (IsMatchItemIn(ap->accesslist,MapAddress(conn->ipaddr)) || 
IsRegexItemIn(ap->accesslist,conn->hostname))
+      if 
(IsHostIn(ap->accesslist,MapAddress(conn->ipaddr),conn->username,conn->hostname))
          {
          access = false;
          CfOut(cf_verbose,"","Host %s explicitly denied access to 
%s\n",conn->hostname,name);
@@ -2148,8 +2147,7 @@
       if (FullTextMatch(ap->path,rp->item))
          {
          /* We have a pattern covering this class - so are we allowed to 
activate it? */
-         if (IsMatchItemIn(ap->accesslist,MapAddress(conn->ipaddr)) ||
-             IsRegexItemIn(ap->accesslist,conn->hostname) ||
+         if 
(IsHostIn(ap->accesslist,MapAddress(conn->ipaddr),conn->username,conn->hostname)
 ||
              IsRegexItemIn(ap->accesslist,userid1) ||
              IsRegexItemIn(ap->accesslist,userid2) ||
              IsRegexItemIn(ap->accesslist,conn->username)
@@ -3279,7 +3277,7 @@
       {
       /* If we find a key, but it doesn't match, see if we permit dynamical IP 
addressing */
       
-      if ((DHCPLIST != NULL) && 
IsMatchItemIn(DHCPLIST,MapAddress(conn->ipaddr)))
+      if ((DHCPLIST != NULL) && 
IsHostIn(DHCPLIST,MapAddress(conn->ipaddr),conn->username,conn->hostname))
          {
          int result;
          result = 
IsKnownHost(savedkey,key,MapAddress(conn->ipaddr),conn->username);
@@ -3305,11 +3303,11 @@
    
    return true;
    }
-else if ((DHCPLIST != NULL) && 
IsMatchItemIn(DHCPLIST,MapAddress(conn->ipaddr)))
+else if ((DHCPLIST != NULL) && 
IsHostIn(DHCPLIST,MapAddress(conn->ipaddr),conn->username,conn->hostname))
    {
    /* If the host is expected to have a dynamic address, check for the key */
    
-   if ((DHCPLIST != NULL) && IsMatchItemIn(DHCPLIST,MapAddress(conn->ipaddr)))
+   if ((DHCPLIST != NULL) && 
IsHostIn(DHCPLIST,MapAddress(conn->ipaddr),conn->username,conn->hostname))
       {
       int result;
       result = 
IsKnownHost(savedkey,key,MapAddress(conn->ipaddr),conn->username);
@@ -3328,7 +3326,7 @@
 
 /* Finally, if we're still here, we should consider trusting a new key ... */
 
-if ((TRUSTKEYLIST != NULL) && 
IsMatchItemIn(TRUSTKEYLIST,MapAddress(conn->ipaddr)))
+if ((TRUSTKEYLIST != NULL) && 
IsHostIn(TRUSTKEYLIST,MapAddress(conn->ipaddr),conn->username,conn->hostname))
    {
    CfOut(cf_verbose,"","Host %s/%s was found in the list of hosts to 
trust\n",conn->hostname,conn->ipaddr);
    conn->trust = true;
--- src/files_links.c~  2009-09-02 21:19:52.000000000 -0400
+++ src/files_links.c   2009-09-02 21:21:13.000000000 -0400
@@ -114,7 +114,8 @@
 else
    { int off1 = 0, off2 = 0;  /* Link exists */
    
-   DeleteSlash(linkbuf);
+   if (*to && !IsFileSep(to[strlen(to)-1]))
+      DeleteSlash(linkbuf);
    
    if (strncmp(linkbuf,"./",2) == 0)   /* Ignore ./ at beginning */
       {
--- src/logging.c~      2009-08-27 20:48:10.000000000 -0400
+++ src/logging.c       2009-08-27 20:48:16.000000000 -0400
@@ -274,12 +274,14 @@
       {
       CfOut(cf_verbose,""," ?> defining persistent promise result class 
%s\n",(char *)rp->item);
       NewPersistentContext(rp->item,persist,policy);
-      PrependItem(&VHEAP,CanonifyName((char *)rp->item),NULL);
+      if (!IsItemIn(VHEAP, CanonifyName((char *)rp->item)))
+        PrependItem(&VHEAP,CanonifyName((char *)rp->item),NULL);
       }
    else
       {
       CfOut(cf_verbose,""," ?> defining promise result class %s\n",(char 
*)rp->item);
-      PrependItem(&VHEAP,CanonifyName((char *)rp->item),NULL);
+      if (!IsItemIn(VHEAP, CanonifyName((char *)rp->item)))
+        PrependItem(&VHEAP,CanonifyName((char *)rp->item),NULL);
       }
    }
 }
--- src/matching.c~     2009-08-27 12:45:55.000000000 -0400
+++ src/matching.c      2009-08-27 13:23:59.000000000 -0400
@@ -158,16 +158,71 @@
 int IsRegex(char *str)
 
 { char *sp;
+  int ret = false;
+  enum { r_norm, r_norepeat, r_literal } special = r_norepeat;
+  int bracket = 0;
+  int paren = 0;
 
 for (sp = str; *sp != '\0'; sp++)
    {
-   if (strchr("^*+\[]()$",*sp))
+   if (special == r_literal)
       {
-      return true;  /* Maybe */
+      special = r_norm;
+      continue;
+      }
+   else if (*sp == '\\')
+      {
+      special = r_literal;
+      continue;
+      }
+   else if (bracket && *sp != ']')
+      {
+      if (*sp == '[') return false;
+      continue;
+      }
+ 
+   switch (*sp)
+      {
+      case '^':
+        special = (sp == str)?r_norepeat:r_norm;
+        break;
+      case '*':
+      case '+':
+        if (special == r_norepeat) return false;
+        special = r_norepeat;
+        ret = true;
+        break;
+      case '[':
+        special = r_norm;
+        bracket++;
+        ret = true;
+        break;
+      case ']':
+        if (bracket == 0) return false;
+        bracket = 0;
+        special = r_norm;
+        break;
+      case '(':
+        special = r_norepeat;
+        paren++;
+        break;
+      case ')':
+        special = r_norm;
+        paren--;
+        if (paren < 0) return false;
+        break;
+      case '|':
+        special = r_norepeat;
+        if (paren > 0) ret = true;
+        break;
+      default:
+        special = r_norm;
       }
+
    }
 
-return false;
+if (bracket != 0 || paren != 0 || special == r_literal) return false;
+return ret;
 }
 
 /*********************************************************************/
--- src/files_interfaces.c~     2009-09-02 17:24:07.000000000 -0400
+++ src/files_interfaces.c      2009-09-02 17:25:06.000000000 -0400
@@ -647,7 +647,7 @@
    return;
    }
 
-if (IsStringIn(SINGLE_COPY_CACHE,destfile))
+if (IsInListOfRegex(SINGLE_COPY_CACHE,destfile))
    {
    CfOut(cf_inform,""," -> Skipping single-copied file %s\n",destfile);
    return;
@@ -898,7 +898,7 @@
                VerifyCopiedFileAttributes(destfile,&dsb,&ssb,attr,pp);
                }
             
-            if (IsRegexIn(SINGLE_COPY_LIST,destfile))
+            if (IsInListOfRegex(SINGLE_COPY_LIST,destfile))
                {
                IdempPrependRScalar(&SINGLE_COPY_CACHE,destfile,CF_SCALAR);
                }
@@ -924,7 +924,7 @@
          otherwise we can get oscillations between multipe versions if type
          is based on a checksum */
 
-      if (IsRegexIn(SINGLE_COPY_LIST,destfile))
+      if (IsInListOfRegex(SINGLE_COPY_LIST,destfile))
          {
          IdempPrependRScalar(&SINGLE_COPY_CACHE,destfile,CF_SCALAR);
          }
_______________________________________________
Bug-cfengine mailing list
Bug-cfengine@cfengine.org
https://cfengine.org/mailman/listinfo/bug-cfengine

Reply via email to