[haiku-commits] BRANCH HaikuPM-github.package-management [be2254e] src/servers/package

  • From: HaikuPM-github.package-management <community@xxxxxxxxxxxx>
  • To: haiku-commits@xxxxxxxxxxxxx
  • Date: Thu, 19 Sep 2013 00:00:31 +0200 (CEST)

added 2 changesets to branch 'refs/remotes/HaikuPM-github/package-management'
old head: 976b547224ff78d2f15a4df1413f790cba9bc98f
new head: be2254e30db907dc1a8b26dd3c3b9dde014bb385
overview: https://github.com/haiku/HaikuPM/compare/976b547...be2254e

----------------------------------------------------------------------------

8b600ba: package daemon: Use CommitTransactionHandler in all cases
  
  ... also when only activating/deactivating already moved packages.

be2254e: package daemon: Handle post-installation scripts, users/groups
  
  ... specified by a package when it is going to be activated. We don't
  try to remove users/groups when deactivating packages yet, nor is the
  user properly identified in all error cases.

                                    [ Ingo Weinhold <ingo_weinhold@xxxxxx> ]

----------------------------------------------------------------------------

1 file changed, 258 insertions(+), 17 deletions(-)
src/servers/package/Volume.cpp | 275 ++++++++++++++++++++++++++++++++++---

############################################################################

Commit:      8b600ba48deafbe63747e28b705551b00adb00a7
Author:      Ingo Weinhold <ingo_weinhold@xxxxxx>
Date:        Sun Sep 15 10:59:20 2013 UTC

package daemon: Use CommitTransactionHandler in all cases

... also when only activating/deactivating already moved packages.

----------------------------------------------------------------------------

diff --git a/src/servers/package/Volume.cpp b/src/servers/package/Volume.cpp
index 7007b0d..61ca65f 100644
--- a/src/servers/package/Volume.cpp
+++ b/src/servers/package/Volume.cpp
@@ -297,23 +297,25 @@ struct Volume::CommitTransactionHandler {
                                "no packages to activate or deactivate");
                }
 
-               // create an old state directory
-               _CreateOldStateDirectory(reply);
-
-               // move packages to deactivate to old state directory
-               _RemovePackagesToDeactivate();
+               _ApplyChanges(reply);
+       }
 
-               // move packages to activate to packages directory
-               _AddPackagesToActivate();
+       void HandleRequest(const PackageSet& packagesAdded,
+               const PackageSet& packagesRemoved)
+       {
+               // Copy package sets to 
fPackagesToActivate/fPackagesToDeactivate. The
+               // given sets are assumed to be identical to the ones specified 
in the
+               // constructor invocation (fPackagesAlreadyAdded,
+               // fPackagesAlreadyRemoved).
+               for (PackageSet::const_iterator it = packagesAdded.begin();
+                       it != packagesAdded.end(); ++it) {
+                       if (!fPackagesToActivate.AddItem(*it))
+                               throw std::bad_alloc();
+               }
 
-               // activate/deactivate packages
-               fVolume->_ChangePackageActivation(fAddedPackages, 
fRemovedPackages);
+               fPackagesToDeactivate = packagesRemoved;
 
-               // removed packages have been deleted, new packages shall not 
be deleted
-               fAddedPackages.clear();
-               fRemovedPackages.clear();
-               fPackagesToActivate.MakeEmpty(false);
-               fPackagesToDeactivate.clear();
+               _ApplyChanges(NULL);
        }
 
        void Revert()
@@ -439,6 +441,27 @@ private:
                }
        }
 
+       void _ApplyChanges(BMessage* reply)
+       {
+               // create an old state directory
+               _CreateOldStateDirectory(reply);
+
+               // move packages to deactivate to old state directory
+               _RemovePackagesToDeactivate();
+
+               // move packages to activate to packages directory
+               _AddPackagesToActivate();
+
+               // activate/deactivate packages
+               fVolume->_ChangePackageActivation(fAddedPackages, 
fRemovedPackages);
+
+               // removed packages have been deleted, new packages shall not 
be deleted
+               fAddedPackages.clear();
+               fRemovedPackages.clear();
+               fPackagesToActivate.MakeEmpty(false);
+               fPackagesToDeactivate.clear();
+       }
+
        void _CreateOldStateDirectory(BMessage* reply)
        {
                // construct a nice name from the current date and time
@@ -1187,15 +1210,29 @@ Volume::ProcessPendingPackageActivationChanges()
        if (!HasPendingPackageActivationChanges())
                return;
 
+       // perform the request
+       CommitTransactionHandler handler(this, fPackagesToBeActivated,
+               fPackagesToBeDeactivated);
+       int32 error;
        try {
-               _ChangePackageActivation(fPackagesToBeActivated,
-                       fPackagesToBeDeactivated);
+               handler.HandleRequest(fPackagesToBeActivated, 
fPackagesToBeDeactivated);
+               error = B_DAEMON_OK;
        } catch (Exception& exception) {
+               error = exception.Error();
                ERROR("Volume::ProcessPendingPackageActivationChanges(): 
package "
                        "activation failed: %s\n", 
exception.ToString().String());
 // TODO: Notify the user!
+       } catch (std::bad_alloc& exception) {
+               error = B_NO_MEMORY;
+               ERROR("Volume::ProcessPendingPackageActivationChanges(): 
package "
+                       "activation failed: out of memory\n");
+// TODO: Notify the user!
        }
 
+       // revert on error
+       if (error != B_DAEMON_OK)
+               handler.Revert();
+
        // clear the activation/deactivation sets in any event
        fPackagesToBeActivated.clear();
        fPackagesToBeDeactivated.clear();

############################################################################

Commit:      be2254e30db907dc1a8b26dd3c3b9dde014bb385
Author:      Ingo Weinhold <ingo_weinhold@xxxxxx>
Date:        Wed Sep 18 21:55:13 2013 UTC

package daemon: Handle post-installation scripts, users/groups

... specified by a package when it is going to be activated. We don't
try to remove users/groups when deactivating packages yet, nor is the
user properly identified in all error cases.

----------------------------------------------------------------------------

diff --git a/src/servers/package/Volume.cpp b/src/servers/package/Volume.cpp
index 61ca65f..0e732f8 100644
--- a/src/servers/package/Volume.cpp
+++ b/src/servers/package/Volume.cpp
@@ -10,11 +10,15 @@
 #include "Volume.h"
 
 #include <errno.h>
+#include <grp.h>
+#include <pwd.h>
 #include <stdlib.h>
 #include <sys/stat.h>
 #include <time.h>
 #include <unistd.h>
 
+#include <string>
+
 #include <Directory.h>
 #include <Entry.h>
 #include <File.h>
@@ -40,6 +44,8 @@
 
 using namespace BPackageKit::BPrivate;
 
+typedef std::set<std::string> StringSet;
+
 
 static const char* const kPackageFileNameExtension = ".hpkg";
 static const char* const kAdminDirectoryName
@@ -54,6 +60,8 @@ static const bigtime_t kHandleNodeMonitorEvents = 'nmon';
 static const bigtime_t kNodeMonitorEventHandlingDelay = 500000;
 static const bigtime_t kCommunicationTimeout = 1000000;
 
+const char* const kShellEscapeCharacters = " ~`#$&*()\\|[]{};'\"<>?!";
+
 
 // #pragma mark - Listener
 
@@ -259,7 +267,9 @@ struct Volume::CommitTransactionHandler {
                fAddedPackages(),
                fRemovedPackages(),
                fPackagesAlreadyAdded(packagesAlreadyAdded),
-               fPackagesAlreadyRemoved(packagesAlreadyRemoved)
+               fPackagesAlreadyRemoved(packagesAlreadyRemoved),
+               fAddedGroups(),
+               fAddedUsers()
        {
        }
 
@@ -326,6 +336,9 @@ struct Volume::CommitTransactionHandler {
                // move packages to deactivate back to packages directory
                _RevertRemovePackagesToDeactivate();
 
+               // revert user and group changes
+               _RevertUserGroupChanges();
+
                // remove old state directory
                _RemoveOldStateDirectory();
        }
@@ -455,6 +468,9 @@ private:
                // activate/deactivate packages
                fVolume->_ChangePackageActivation(fAddedPackages, 
fRemovedPackages);
 
+               // run post-installation scripts
+               _RunPostInstallScripts();
+
                // removed packages have been deleted, new packages shall not 
be deleted
                fAddedPackages.clear();
                fRemovedPackages.clear();
@@ -576,6 +592,7 @@ private:
                        if (fPackagesAlreadyAdded.find(package)
                                        != fPackagesAlreadyAdded.end()) {
                                fAddedPackages.insert(package);
+                               _PreparePackageToActivate(package);
                                continue;
                        }
 
@@ -606,9 +623,129 @@ private:
 
                        // also add the package to the volume
                        fVolume->_AddPackage(package);
+
+                       _PreparePackageToActivate(package);
+               }
+       }
+
+       void _PreparePackageToActivate(Package* package)
+       {
+               // add groups
+               const BStringList& groups = package->Info().Groups();
+               int32 count = groups.CountStrings();
+               for (int32 i = 0; i < count; i++)
+                       _AddGroup(package, groups.StringAt(i));
+
+               // add users
+               const BObjectList<BUser>& users = package->Info().Users();
+               for (int32 i = 0; const BUser* user = users.ItemAt(i); i++)
+                       _AddUser(package, *user);
+
+               // handle global writable files
+               const BObjectList<BGlobalWritableFileInfo>& files
+                       = package->Info().GlobalWritableFileInfos();
+               for (int32 i = 0; const BGlobalWritableFileInfo* file = 
files.ItemAt(i);
+                       i++) {
+                       _AddGlobalWritableFile(package, *file);
+               }
+       }
+
+       void _AddGroup(Package* package, const BString& groupName)
+       {
+               // Check whether the group already exists.
+               char buffer[256];
+               struct group groupBuffer;
+               struct group* groupFound;
+               int error = getgrnam_r(groupName, &groupBuffer, buffer, 
sizeof(buffer),
+                       &groupFound);
+               if ((error == 0 && groupFound != NULL) || error == ERANGE)
+                       return;
+
+               // add it
+               fAddedGroups.insert(groupName.String());
+
+               std::string commandLine("groupadd ");
+               commandLine += _ShellEscapeString(groupName).String();
+
+               if (system(commandLine.c_str()) != 0) {
+                       fAddedGroups.erase(groupName.String());
+                       throw Exception(error,
+                               BString().SetToFormat("failed to add group 
\%s\"",
+                                       groupName.String()),
+                               package->FileName());
+               }
+       }
+
+       void _AddUser(Package* package, const BUser& user)
+       {
+               // Check whether the user already exists.
+               char buffer[256];
+               struct passwd passwdBuffer;
+               struct passwd* passwdFound;
+               int error = getpwnam_r(user.Name(), &passwdBuffer, buffer,
+                       sizeof(buffer), &passwdFound);
+               if ((error == 0 && passwdFound != NULL) || error == ERANGE)
+                       return;
+
+               // add it
+               fAddedUsers.insert(user.Name().String());
+
+               std::string commandLine("useradd ");
+
+               if (!user.RealName().IsEmpty()) {
+                       commandLine += std::string("-n ")
+                               + _ShellEscapeString(user.RealName()).String() 
+ " ";
+               }
+
+               if (!user.Home().IsEmpty()) {
+                       commandLine += std::string("-d ")
+                               + _ShellEscapeString(user.Home()).String() + " 
";
+               }
+
+               if (!user.Shell().IsEmpty()) {
+                       commandLine += std::string("-s ")
+                               + _ShellEscapeString(user.Shell()).String() + " 
";
+               }
+
+               if (!user.Groups().IsEmpty()) {
+                       commandLine += std::string("-g ")
+                               + 
_ShellEscapeString(user.Groups().First()).String() + " ";
+               }
+
+               commandLine += _ShellEscapeString(user.Name()).String();
+
+               if (system(commandLine.c_str()) != 0) {
+                       fAddedUsers.erase(user.Name().String());
+                       throw Exception(error,
+                               BString().SetToFormat("failed to add user 
\%s\"",
+                                       user.Name().String()),
+                               package->FileName());
+               }
+
+               // add the supplementary groups
+               int32 groupCount = user.Groups().CountStrings();
+               for (int32 i = 1; i < groupCount; i++) {
+                       commandLine = std::string("groupmod -A ")
+                               + _ShellEscapeString(user.Name()).String()
+                               + " "
+                               + 
_ShellEscapeString(user.Groups().StringAt(i)).String();
+                       if (system(commandLine.c_str()) != 0) {
+                               fAddedUsers.erase(user.Name().String());
+                               throw Exception(error,
+                                       BString().SetToFormat("failed to add 
user \%s\" to group "
+                                               "\"%s\"", user.Name().String(),
+                                               
user.Groups().StringAt(i).String()),
+                                       package->FileName());
+                       }
                }
        }
 
+       void _AddGlobalWritableFile(Package* package,
+               const BGlobalWritableFileInfo& file)
+       {
+// TODO:...
+       }
+
        void _RevertAddPackagesToActivate()
        {
                if (fAddedPackages.empty())
@@ -709,6 +846,27 @@ private:
                }
        }
 
+       void _RevertUserGroupChanges()
+       {
+               // delete users
+               for (StringSet::const_iterator it = fAddedUsers.begin();
+                       it != fAddedUsers.end(); ++it) {
+                       std::string commandLine("userdel ");
+                       commandLine += _ShellEscapeString(it->c_str()).String();
+                       if (system(commandLine.c_str()) != 0)
+                               ERROR("failed to remove user \"%s\"\n", 
it->c_str());
+               }
+
+               // delete groups
+               for (StringSet::const_iterator it = fAddedGroups.begin();
+                       it != fAddedGroups.end(); ++it) {
+                       std::string commandLine("groupdel ");
+                       commandLine += _ShellEscapeString(it->c_str()).String();
+                       if (system(commandLine.c_str()) != 0)
+                               ERROR("failed to remove group \"%s\"\n", 
it->c_str());
+               }
+       }
+
        void _RemoveOldStateDirectory()
        {
                if (fOldStateDirectory.InitCheck() != B_OK)
@@ -736,6 +894,50 @@ private:
                }
        }
 
+       void _RunPostInstallScripts()
+       {
+               for (PackageSet::iterator it = fAddedPackages.begin();
+                       it != fAddedPackages.end(); ++it) {
+                       Package* package = *it;
+                       const BStringList& scripts = 
package->Info().PostInstallScripts();
+                       int32 count = scripts.CountStrings();
+                       for (int32 i = 0; i < count; i++)
+                               _RunPostInstallScript(package, 
scripts.StringAt(i));
+               }
+       }
+
+       void _RunPostInstallScript(Package* package, const BString& script)
+       {
+               BDirectory rootDir(&fVolume->fRootDirectoryRef);
+               BPath scriptPath(&rootDir, script);
+               status_t error = scriptPath.InitCheck();
+               if (error != B_OK) {
+                       
ERROR("Volume::CommitTransactionHandler::_RunPostInstallScript(): "
+                               "failed get path of post-installation script 
\"%s\" of package "
+                               "%s: %s\n", script.String(), 
package->FileName().String(),
+                               strerror(error));
+// TODO: Notify the user!
+                       return;
+               }
+
+               if (system(scriptPath.Path()) != 0) {
+                       
ERROR("Volume::CommitTransactionHandler::_RunPostInstallScript(): "
+                               "running post-installation script \"%s\" of 
package %s "
+                               "failed: %s\n", script.String(), 
package->FileName().String(),
+                               strerror(error));
+// TODO: Notify the user!
+               }
+       }
+
+       BString _ShellEscapeString(const BString& string)
+       {
+               BString result(string);
+               result.CharacterEscape(kShellEscapeCharacters, '\\');
+               if (result.IsEmpty())
+                       throw std::bad_alloc();
+               return result;
+       }
+
 private:
        Volume*                         fVolume;
        PackageList                     fPackagesToActivate;
@@ -747,6 +949,8 @@ private:
        BDirectory                      fOldStateDirectory;
        BString                         fOldStateDirectoryName;
        node_ref                        fTransactionDirectoryRef;
+       StringSet                       fAddedGroups;
+       StringSet                       fAddedUsers;
 };
 
 


Other related posts:

  • » [haiku-commits] BRANCH HaikuPM-github.package-management [be2254e] src/servers/package - HaikuPM-github . package-management