Index: cfengine-trunk/src/package.c
===================================================================
--- cfengine-trunk.orig/src/package.c
+++ cfengine-trunk/src/package.c
@@ -309,18 +309,30 @@ int UpgradePackage(struct Package *ptr,c
  
 Verbose("Package upgrade for %s: %s\n", PKGMGRTEXT[pkgmgr], name );
 
-PackageList(ptr,name,pkgmgr,version,cmp,&removelist);
-   
-if (RemovePackage(ptr,pkgmgr,&removelist))
+if ((ptr->pkgmgr == pkgmgr_freebsd) || (ptr->pkgmgr == pkgmgr_sun))
    {
-   AppendItem(&addlist, name, NULL);
-   result = InstallPackage(ptr,pkgmgr,&addlist);
+   /* Handle package managers with independant removes/installs */
+
+   PackageList(ptr,name,pkgmgr,version,cmp,&removelist);
+
+   if (RemovePackage(ptr,pkgmgr,&removelist))
+      {
+      AppendItem(&addlist, name, NULL);
+      result = InstallPackage(ptr,pkgmgr,&addlist);
+      }
+   else
+      {
+      CfLog(cfinform,"Package cannot be upgraded because the old version was not removed.\n\n","");
+      AuditLog(ptr->logaudit,ptr->audit,ptr->lineno,"Package not upgraded - another version in the way",CF_FAIL);
+      result = 0;
+      }
    }
 else
    {
-   CfLog(cfinform,"Package cannot be upgraded because the old version was not removed.\n\n","");
-   AuditLog(ptr->logaudit,ptr->audit,ptr->lineno,"Package not upgraded - another version in the way",CF_FAIL);
-   result = 0;
+   /* Handle package managers that do atomic upgrades */
+
+   AppendItem(&addlist, name, NULL);
+   result = InstallPackage(ptr,pkgmgr,&addlist);
    }
 
 DeleteItemList(removelist);
@@ -348,30 +360,42 @@ switch(pkgmgr)
    {
    case pkgmgr_dpkg:
 
-       if (!GetMacroValue(CONTEXTID,"DPKGRemoveCommand"))
-          {
-          CfLog(cferror,"DPKGRemoveCommand NOT Set.  Package Removal Not Possible!\n","");
-          return 0;
-          }
-       strncpy(rawdelcmd, GetMacroValue(CONTEXTID,"DPKGRemoveCommand"),CF_BUFSIZE);
-       break;
-       
+      if (!GetMacroValue(CONTEXTID,"DPKGRemoveCommand"))
+         {
+         CfLog(cferror,"DPKGRemoveCommand NOT Set.  Package Removal Not Possible!\n","");
+         return 0;
+         }
+      strncpy(rawdelcmd, GetMacroValue(CONTEXTID,"DPKGRemoveCommand"), CF_BUFSIZE);
+      break;
+
    case pkgmgr_freebsd:
 
-       if (!GetMacroValue(CONTEXTID,"FreeBSDRemoveCommand"))
-          {
-          strncpy(rawdelcmd, "/usr/sbin/pkg_delete %s", 23 );
-          }
-       else
-          {
-          strncpy(rawdelcmd, GetMacroValue(CONTEXTID,"FreeBSDRemoveCommand"),CF_BUFSIZE);
-          }
-       break;
-       
-      default:
-          CfLog(cferror,"RemovePackage: Package removal not yet implemented for this package manager.\n","p");
-          AuditLog(ptr->logaudit,ptr->audit,ptr->lineno,"No support for package removal",CF_NOP);
-          break;
+      if (!GetMacroValue(CONTEXTID,"FreeBSDRemoveCommand"))
+         {
+         strncpy(rawdelcmd, "/usr/sbin/pkg_delete %s", CF_BUFSIZE);
+         }
+      else
+         {
+         strncpy(rawdelcmd, GetMacroValue(CONTEXTID,"FreeBSDRemoveCommand"), CF_BUFSIZE);
+         }
+      break;
+
+   case pkgmgr_portage:
+
+      if (!GetMacroValue(CONTEXTID,"PortageRemoveCommand"))
+         {
+         strncpy(rawdelcmd, "/usr/bin/emerge -C %s", CF_BUFSIZE);
+         }
+      else
+         {
+         strncpy(rawdelcmd, GetMacroValue(CONTEXTID,"PortageRemoveCommand"), CF_BUFSIZE);
+         }
+      break;
+
+   default:
+      CfLog(cferror,"RemovePackage: Package removal not yet implemented for this package manager.\n","p");
+      AuditLog(ptr->logaudit,ptr->audit,ptr->lineno,"No support for package removal",CF_NOP);
+      break;
    }
 
 
@@ -453,9 +477,8 @@ if (cmd_tail = strstr(rawcmd, "%s"))
    cmd_tail += 2;
    cmd_tail_len = strlen(cmd_tail);
    --cmd_args;
+   strncpy(resolvedcmd, rawcmd, CF_BUFSIZE*2);
    }
-   
-strncpy(resolvedcmd, rawcmd, CF_BUFSIZE*2);
 
 Verbose("Package manager will be invoked as %s\n", resolvedcmd);
 
@@ -481,7 +504,7 @@ for (package = pkglist; package != NULL;
    else
       {
       Verbose("BuildCommandLine(): Adding package '%s' to the list.\n", package->name);
-      
+
       strncpy(cmd_ptr, package->name, &resolvedcmd[CF_BUFSIZE*2] - cmd_ptr);
       cmd_ptr += strlen(package->name);
       *cmd_ptr++ = ' ';
@@ -1393,7 +1416,7 @@ int PortagePackageCheck(char *package,ch
   char *nameptr = NULL;
 
 /* Create a working copy of the name */
-strncpy(pkgname, package, CF_BUFSIZE);
+strncpy(pkgname, package, CF_BUFSIZE - 1);
 
 /* Test if complete package atom was given */
 if (pkgname[0] == '=' || pkgname[0] == '<' || pkgname[0] == '>')
@@ -1441,9 +1464,9 @@ if ((pp = cfpopen(VBUFF, "r")) == NULL)
 while(!feof(pp))
    {
    *VBUFF = '\0';
-   
+
    ReadLine(VBUFF,CF_BUFSIZE,pp);
-   
+
    if (*VBUFF != '\0')
       {
       AppendItem(&ebuildlist,VBUFF,"");
@@ -1454,11 +1477,11 @@ cfpclose(pp);
 
 if (ebuildlist == NULL)
    {
-   Verbose("PortageCheckPackage(): Package %s not installed.\n", nameptr);
+   Verbose("PortagePackageCheck(): Package %s not installed.\n", nameptr);
    return 0;
    }
 
-Verbose("PortageCheckPackage(): Requested %s %s %s\n", nameptr, CMPSENSETEXT[cmp],(version[0] ? version : "ANY"));
+Verbose("PortagePackageCheck(): Requested %s %s %s\n", nameptr, CMPSENSETEXT[cmp],(version[0] ? version : "ANY"));
 
 /* If no version was specified, return successful (found something) */
 if (!version[0])
@@ -1470,7 +1493,7 @@ if (!version[0])
 /* Iterate through all installed versions until match is found */
 for (ebuild = ebuildlist; ebuild != NULL; ebuild=ebuild->next)
    {
-   Verbose("PortageCheckPackage(): Trying installed version %s\n", ebuild->name);
+   Verbose("PortagePackageCheck(): Trying installed version %s\n", ebuild->name);
 
    /* Run comparison tool to do the grunt work */
    snprintf(VBUFF,CF_BUFSIZE,"/usr/bin/qatom -cC %s %s-%s", ebuild->name, nameptr, version);
@@ -1480,7 +1503,7 @@ for (ebuild = ebuildlist; ebuild != NULL
       CfLog(cferror,"Could not execute the qatom command. Is portage-utils installed?\n","");
       continue;
       }
-  
+
    if (feof(pp))
       {
       snprintf(OUTPUT,CF_BUFSIZE,"Internal error!  No output from %s.",VBUFF);
@@ -1539,8 +1562,168 @@ return 0;
 /*********************************************************************/
 
 int PortagePackageList(char *package, char *version, enum cmpsense cmp, struct Item **pkglist)
-{
-return 0; /* not implemented yet */
+{ FILE *pp;
+  struct Item *ebuildlist = NULL;
+  struct Item *ebuild = NULL;
+  int match = 0;
+  int nummatches = 0;
+  char *result = NULL;
+  char pkgname[CF_BUFSIZE] = {0};
+  char pkgatom[CF_BUFSIZE] = {0};
+  char *nameptr = NULL;
+
+/* Create a working copy of the name */
+strncpy(pkgname, package, CF_BUFSIZE - 1);
+
+/* Test if complete package atom was given */
+if (pkgname[0] == '=' || pkgname[0] == '<' || pkgname[0] == '>')
+   {
+   /* Strip version */
+   nameptr = strchr(pkgname, '/');
+   if (nameptr == NULL)
+      {
+      /* Package does not include category, which is fine */
+      nameptr = pkgname;
+      }
+   while (!xisdigit(nameptr[1]))
+      {
+      nameptr = strchr(++nameptr, '-');
+      if (nameptr == NULL)
+         {
+         snprintf(OUTPUT,CF_BUFSIZE,"Unable to parse version from %s!\n",pkgname);
+         CfLog(cferror,OUTPUT,"");
+         return -1;
+         }
+      }
+   nameptr[0] = '\0';
+
+   /* Strip comparison operator (or rather, seek past) */
+   nameptr = pkgname;
+   while (!xisalpha(nameptr[0]))
+      {
+      ++nameptr;
+      }
+   }
+else
+   {
+   nameptr = pkgname;
+   }
+
+/* Search for installed versions of package */
+snprintf(VBUFF,CF_BUFSIZE,"/usr/bin/qlist -IevC %s",nameptr);
+
+if ((pp = cfpopen(VBUFF, "r")) == NULL)
+   {
+   CfLog(cferror,"Could not execute the qlist command. Is portage-utils installed?\n","");
+   return -1;
+   }
+
+while(!feof(pp))
+   {
+   *VBUFF = '\0';
+
+   ReadLine(VBUFF,CF_BUFSIZE,pp);
+
+   if (*VBUFF != '\0')
+      {
+      AppendItem(&ebuildlist,VBUFF,"");
+      }
+   }
+
+cfpclose(pp);
+
+if (ebuildlist == NULL)
+   {
+   Verbose("PortagePackageList(): Package %s not installed.\n", nameptr);
+   return 0;
+   }
+
+Verbose("PortagePackageList(): Requested %s %s %s\n", nameptr, CMPSENSETEXT[cmp],(version[0] ? version : "ANY"));
+
+/* Iterate through all installed versions and register matches */
+for (ebuild = ebuildlist; ebuild != NULL; ebuild=ebuild->next)
+   {
+   Verbose("PortagePackageList(): Trying installed version %s\n", ebuild->name);
+
+   /* If no version was specified, register ebuild */
+   if (!version[0])
+      {
+      strncpy(pkgatom, "=", CF_BUFSIZE - 1);
+      strncat(pkgatom, ebuild->name, CF_BUFSIZE - 2);
+      snprintf(OUTPUT,CF_BUFSIZE,"Package atom matches: %s\n",pkgatom);
+      AppendItem(pkglist,pkgatom,"");
+      ++nummatches;
+      continue;
+      }
+
+   /* Run comparison tool to do the grunt work */
+   snprintf(VBUFF,CF_BUFSIZE,"/usr/bin/qatom -cC %s %s-%s", ebuild->name, nameptr, version);
+
+   if ((pp = cfpopen(VBUFF, "r")) == NULL)
+      {
+      CfLog(cferror,"Could not execute the qatom command. Is portage-utils installed?\n","");
+      continue;
+      }
+
+   if (feof(pp))
+      {
+      snprintf(OUTPUT,CF_BUFSIZE,"Internal error!  No output from %s.",VBUFF);
+      CfLog(cferror,OUTPUT,"");
+      continue;
+      }
+
+   /* Format of output is `package < package' */
+   *VBUFF = '\0';
+   ReadLine(VBUFF,CF_BUFSIZE,pp);
+   Verbose("PortagePackageList(): Result %s\n",VBUFF);
+   cfpclose(pp);
+
+   /* Find first space, give up otherwise */
+   result = strchr(VBUFF, ' ');
+   if (result == NULL) continue;
+
+   /* Relocate to right of space (the comparison symbol) */
+   ++result;
+
+   switch(cmp)
+      {
+      case cmpsense_gt:
+         match = (*result == *CMPSENSEOPERAND[cmpsense_gt]);
+         break;
+      case cmpsense_ge:
+         match = (*result == *CMPSENSEOPERAND[cmpsense_gt] || *result == *CMPSENSEOPERAND[cmpsense_eq]);
+         break;
+      case cmpsense_lt:
+         match = (*result == *CMPSENSEOPERAND[cmpsense_lt]);
+         break;
+      case cmpsense_le:
+         match = (*result == *CMPSENSEOPERAND[cmpsense_lt] || *result == *CMPSENSEOPERAND[cmpsense_eq]);
+         break;
+      case cmpsense_eq:
+         match = (*result == *CMPSENSEOPERAND[cmpsense_eq]);
+         break;
+      case cmpsense_ne:
+         match = (*result != *CMPSENSEOPERAND[cmpsense_eq]);
+         break;
+      }
+
+   /* Register ebuild on finding a match */
+   if (match)
+      {
+      strncpy(pkgatom, "=", CF_BUFSIZE - 1);
+      strncat(pkgatom, ebuild->name, CF_BUFSIZE - 2);
+      snprintf(OUTPUT,CF_BUFSIZE,"Package atom matches: %s\n",pkgatom);
+      AppendItem(pkglist,pkgatom,"");
+      ++nummatches;
+      continue;
+      }
+   }
+
+DeleteItemList(ebuildlist);
+
+/* Return whether matches found */
+return nummatches > 0 ? 1 : 0;
+
 }
 
 /*********************************************************************/
Index: cfengine-trunk/src/do.c
===================================================================
--- cfengine-trunk.orig/src/do.c
+++ cfengine-trunk/src/do.c
@@ -2881,7 +2881,6 @@ for (ptr = VPKG; ptr != NULL; ptr=ptr->n
 
       if (ptr->action == pkgaction_remove) 
          {
-         AppendItem(&pending_pkgs,name,NULL);
          PackageList(ptr,name,ptr->pkgmgr,ptr->ver,ptr->cmp,&pending_pkgs);
          }
       else if (ptr->action == pkgaction_upgrade)
