PackageInstaller: Run install scripts in the correct directory

* From debugging with the Gobe and Moho installer, scripts define which
   folder to run them from. The PackageInstaller is supposed to run the script
   in that working directory. The parser seems to have the correct folder in
   "installPath" when adding the script as PackageItem, but that code is rather
   horrible. I've changed it so PackageScript items also set the path, use
   InitPath() to obtain the final working directory and set it before running
   the script.
 * Both Moho and Gobe create the Deskbar link from that script, the folder
   is rewritten in the script via ReplaceAll().
 * Correctly running the script makes a bug visible: Dynamically added files
   in the install location by these scripts are not removed when uninstalling
   the package. When re-installing a package, it is first uninstalled and this
   currently gives an error for both Moho and Gobe, since they create some
   links in these scripts which never worked before. To install again, the
   install folder needs to be deleted manually.
 * Some cleanup along the way... sorry.
This commit is contained in:
Stephan Aßmus
2014-02-16 23:32:01 +01:00
parent 4407020ba4
commit 3f5014ec86
5 changed files with 103 additions and 62 deletions
+5 -2
View File
@@ -1024,8 +1024,11 @@ PackageInfo::Parse()
localType, ctime, mtime, mode, offset, size); localType, ctime, mtime, mode, offset, size);
} }
} else if (element == P_SCRIPT) { } else if (element == P_SCRIPT) {
fScripts.AddItem(new PackageScript(fPackageFile, offset, size, parser_debug("Adding the script %s!\n",
originalSize)); nameString.String());
fScripts.AddItem(new PackageScript(fPackageFile,
installDirectory, offset, size, originalSize));
} else { } else {
// If the directory tree count is equal to zero, this means all // If the directory tree count is equal to zero, this means all
// directory trees have been closed and a padding sequence means the // directory trees have been closed and a padding sequence means the
+3 -2
View File
@@ -202,7 +202,7 @@ PackageInstall::_Install()
fItemExistsPolicy = P_EXISTS_NONE; fItemExistsPolicy = P_EXISTS_NONE;
const char *installPath = fParent->CurrentPath()->Path(); const char* installPath = fParent->CurrentPath()->Path();
for (uint32 i = 0; i < n; i++) { for (uint32 i = 0; i < n; i++) {
ItemState state(fItemExistsPolicy); ItemState state(fItemExistsPolicy);
PackageItem* item = static_cast<PackageItem*>(type->items.ItemAt(i)); PackageItem* item = static_cast<PackageItem*>(type->items.ItemAt(i));
@@ -245,10 +245,11 @@ PackageInstall::_Install()
fCurrentScriptLocker.Lock(); fCurrentScriptLocker.Lock();
fCurrentScript = script; fCurrentScript = script;
status_t status = script->DoInstall(); status_t status = script->DoInstall(installPath);
if (status != B_OK) { if (status != B_OK) {
fprintf(stderr, "Error while running script: %s\n", fprintf(stderr, "Error while running script: %s\n",
strerror(status)); strerror(status));
fCurrentScriptLocker.Unlock();
return P_MSG_I_ERROR; return P_MSG_I_ERROR;
} }
fCurrentScriptLocker.Unlock(); fCurrentScriptLocker.Unlock();
+21 -16
View File
@@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2010, Haiku, Inc. * Copyright (c) 2010-2014, Haiku, Inc.
* Distributed under the terms of the MIT license. * Distributed under the terms of the MIT license.
* *
* Author: * Author:
@@ -8,8 +8,10 @@
#ifndef PACKAGE_INSTALL_H #ifndef PACKAGE_INSTALL_H
#define PACKAGE_INSTALL_H #define PACKAGE_INSTALL_H
#include <Locker.h> #include <Locker.h>
class PackageView; class PackageView;
class PackageScript; class PackageScript;
@@ -19,25 +21,28 @@ enum {
P_MSG_I_ERROR = 'pier' P_MSG_I_ERROR = 'pier'
}; };
class PackageInstall { class PackageInstall {
public: public:
PackageInstall(PackageView *parent); PackageInstall(PackageView* parent);
~PackageInstall(); ~PackageInstall();
status_t Start(); status_t Start();
void Stop(); void Stop();
void Install(); void Install();
private: private:
uint32 _Install(); uint32 _Install();
PackageView *fParent; private:
thread_id fThreadId; PackageView* fParent;
BLocker fIdLocker; thread_id fThreadId;
BLocker fIdLocker;
PackageScript *fCurrentScript; PackageScript* fCurrentScript;
BLocker fCurrentScriptLocker; // XXX: will we need this? BLocker fCurrentScriptLocker;
int32 fItemExistsPolicy; int32 fItemExistsPolicy;
}; };
#endif
#endif // PACKAGE_INSTALL_H
+60 -32
View File
@@ -130,10 +130,8 @@ inflate_file_to_file(BFile *in, uint64 in_size, BFile *out, uint64 out_size)
(void)inflateEnd(&stream); (void)inflateEnd(&stream);
return B_ERROR; return B_ERROR;
} }
} } while (stream.avail_out == 0);
while (stream.avail_out == 0); } while (bytes_read != in_size);
}
while (bytes_read != in_size);
(void)inflateEnd(&stream); (void)inflateEnd(&stream);
@@ -144,7 +142,7 @@ inflate_file_to_file(BFile *in, uint64 in_size, BFile *out, uint64 out_size)
// #pragma mark - PackageItem // #pragma mark - PackageItem
PackageItem::PackageItem(BFile *parent, const BString &path, uint8 type, PackageItem::PackageItem(BFile* parent, const BString& path, uint8 type,
uint32 ctime, uint32 mtime, uint64 offset, uint64 size) uint32 ctime, uint32 mtime, uint64 offset, uint64 size)
{ {
SetTo(parent, path, type, ctime, mtime, offset, size); SetTo(parent, path, type, ctime, mtime, offset, size);
@@ -157,7 +155,7 @@ PackageItem::~PackageItem()
void void
PackageItem::SetTo(BFile *parent, const BString &path, uint8 type, uint32 ctime, PackageItem::SetTo(BFile* parent, const BString& path, uint8 type, uint32 ctime,
uint32 mtime, uint64 offset, uint64 size) uint32 mtime, uint64 offset, uint64 size)
{ {
fPackage = parent; fPackage = parent;
@@ -172,7 +170,7 @@ PackageItem::SetTo(BFile *parent, const BString &path, uint8 type, uint32 ctime,
status_t status_t
PackageItem::InitPath(const char *path, BPath *destination) PackageItem::InitPath(const char* path, BPath* destination)
{ {
status_t ret = B_OK; status_t ret = B_OK;
@@ -300,10 +298,10 @@ PackageItem::HandleAttributes(BPath *destination, BNode *node,
status_t status_t
PackageItem::ParseAttribute(uint8 *buffer, BNode *node, char **attrName, PackageItem::ParseAttribute(uint8* buffer, BNode* node, char** attrName,
uint32 *nameSize, uint32 *attrType, uint8 **attrData, uint64 *dataSize, uint32* nameSize, uint32* attrType, uint8** attrData, uint64* dataSize,
uint8 **temp, uint64 *tempSize, uint64 *attrCSize, uint64 *attrOSize, uint8** temp, uint64* tempSize, uint64* attrCSize, uint64* attrOSize,
bool *attrStarted, bool *done) bool* attrStarted, bool* done)
{ {
status_t ret = B_OK; status_t ret = B_OK;
uint32 length; uint32 length;
@@ -415,7 +413,7 @@ PackageItem::ParseAttribute(uint8 *buffer, BNode *node, char **attrName,
status_t status_t
PackageItem::SkipAttribute(uint8 *buffer, bool *attrStarted, bool *done) PackageItem::SkipAttribute(uint8* buffer, bool* attrStarted, bool* done)
{ {
status_t ret = B_OK; status_t ret = B_OK;
uint32 length; uint32 length;
@@ -477,7 +475,7 @@ PackageItem::SkipAttribute(uint8 *buffer, bool *attrStarted, bool *done)
status_t status_t
PackageItem::ParseData(uint8 *buffer, BFile *file, uint64 originalSize, PackageItem::ParseData(uint8* buffer, BFile* file, uint64 originalSize,
bool *done) bool *done)
{ {
status_t ret = B_OK; status_t ret = B_OK;
@@ -513,12 +511,10 @@ PackageItem::ParseData(uint8 *buffer, BFile *file, uint64 originalSize,
return ret; return ret;
} }
parser_debug(" File data inflation complete!\n"); parser_debug(" File data inflation complete!\n");
} } else if (!memcmp(buffer, padding, 7)) {
else if (!memcmp(buffer, padding, 7)) {
*done = true; *done = true;
return ret; return ret;
} } else {
else {
parser_debug("_ParseData unknown tag\n"); parser_debug("_ParseData unknown tag\n");
ret = B_ERROR; ret = B_ERROR;
} }
@@ -530,10 +526,10 @@ PackageItem::ParseData(uint8 *buffer, BFile *file, uint64 originalSize,
// #pragma mark - PackageScript // #pragma mark - PackageScript
PackageScript::PackageScript(BFile *parent, uint64 offset, uint64 size, PackageScript::PackageScript(BFile* parent, const BString& path, uint64 offset,
uint64 originalSize) uint64 size, uint64 originalSize)
: :
PackageItem(parent, NULL, 0, 0, 0, offset, size), PackageItem(parent, path, P_INSTALL_PATH, 0, 0, offset, size),
fOriginalSize(originalSize), fOriginalSize(originalSize),
fThreadId(-1) fThreadId(-1)
{ {
@@ -541,7 +537,7 @@ PackageScript::PackageScript(BFile *parent, uint64 offset, uint64 size,
status_t status_t
PackageScript::DoInstall(const char *path, ItemState *state) PackageScript::DoInstall(const char* path, ItemState* state)
{ {
status_t ret = B_OK; status_t ret = B_OK;
parser_debug("Script: DoInstall() called!\n"); parser_debug("Script: DoInstall() called!\n");
@@ -579,8 +575,29 @@ PackageScript::DoInstall(const char *path, ItemState *state)
break; break;
case P_DATA: case P_DATA:
ret = _ParseScript(buffer, fOriginalSize, &done); {
BString script;
ret = _ParseScript(buffer, fOriginalSize, script, &done);
if (ret == B_OK) {
// Rewrite Deskbar entry targets. NOTE: It would
// also work to Replace("/config/be", "/config...")
// but it would be less save. For example, an app
// could have a folder named "config/be..." inside
// its installation folder.
script.ReplaceAll(
"~/config/be",
"~/config/settings/deskbar/menu");
script.ReplaceAll(
"/boot/home/config/be",
"/boot/home/config/settings/deskbar/menu");
BPath workingDirectory;
ret = InitPath(path, &workingDirectory);
if (ret == B_OK)
ret = _RunScript(workingDirectory.Path(), script);
}
break; break;
}
default: default:
return B_ERROR; return B_ERROR;
@@ -604,7 +621,8 @@ PackageScript::ItemKind()
status_t status_t
PackageScript::_ParseScript(uint8 *buffer, uint64 originalSize, bool *done) PackageScript::_ParseScript(uint8 *buffer, uint64 originalSize,
BString& _script, bool *done)
{ {
status_t ret = B_OK; status_t ret = B_OK;
@@ -640,7 +658,7 @@ PackageScript::_ParseScript(uint8 *buffer, uint64 originalSize, bool *done)
return B_ERROR; return B_ERROR;
} }
uint8 *script = new uint8[original]; uint8* script = new uint8[original];
ret = inflate_data(temp, compressed, script, original); ret = inflate_data(temp, compressed, script, original);
if (ret != B_OK) { if (ret != B_OK) {
parser_debug(" inflate_data failed\n"); parser_debug(" inflate_data failed\n");
@@ -649,7 +667,8 @@ PackageScript::_ParseScript(uint8 *buffer, uint64 originalSize, bool *done)
return ret; return ret;
} }
ret = _RunScript(script, originalSize); _script.SetTo((char*)script, originalSize);
delete[] script; delete[] script;
delete[] temp; delete[] temp;
parser_debug(" Script data inflation complete!\n"); parser_debug(" Script data inflation complete!\n");
@@ -666,18 +685,23 @@ PackageScript::_ParseScript(uint8 *buffer, uint64 originalSize, bool *done)
status_t status_t
PackageScript::_RunScript(uint8 *script, uint32 len) PackageScript::_RunScript(const char* workingDirectory, const BString& script)
{ {
// This function written by Peter Folk <[email protected]> // This function written by Peter Folk <[email protected]>
// and published in the BeDevTalk FAQ, modified for use in the // and published in the BeDevTalk FAQ, modified for use in the
// PackageInstaller // PackageInstaller
// http://www.abisoft.com/faq/BeDevTalk_FAQ.html#FAQ-209 // http://www.abisoft.com/faq/BeDevTalk_FAQ.html#FAQ-209
// Change current working directory to install path
char oldWorkingDirectory[B_PATH_NAME_LENGTH];
getcwd(oldWorkingDirectory, sizeof(oldWorkingDirectory));
chdir(workingDirectory);
// Save current FDs // Save current FDs
int old_in = dup(0); int old_in = dup(0);
int old_out = dup(1); int old_out = dup(1);
int old_err = dup(2); int old_err = dup(2);
int filedes[2]; int filedes[2];
/* Create new pipe FDs as stdin, stdout, stderr */ /* Create new pipe FDs as stdin, stdout, stderr */
@@ -714,12 +738,16 @@ PackageScript::_RunScript(uint8 *script, uint32 len)
resume_thread(fThreadId); resume_thread(fThreadId);
// Write the script // Write the script
if (write(in, script, len) != (int32)len || write(in, "\nexit\n", 6) != 6) { if (write(in, script.String(), script.Length() - 1) != script.Length() - 1
|| write(in, "\nexit\n", 6) != 6) {
parser_debug("Writing script failed\n"); parser_debug("Writing script failed\n");
kill_thread(fThreadId); kill_thread(fThreadId);
return B_ERROR; return B_ERROR;
} }
// Restore current working directory
chdir(oldWorkingDirectory);
return B_OK; return B_OK;
} }
@@ -727,7 +755,7 @@ PackageScript::_RunScript(uint8 *script, uint32 len)
// #pragma mark - PackageDirectory // #pragma mark - PackageDirectory
PackageDirectory::PackageDirectory(BFile *parent, const BString &path, PackageDirectory::PackageDirectory(BFile* parent, const BString& path,
uint8 type, uint32 ctime, uint32 mtime, uint64 offset, uint64 size) uint8 type, uint32 ctime, uint32 mtime, uint64 offset, uint64 size)
: :
PackageItem(parent, path, type, ctime, mtime, offset, size) PackageItem(parent, path, type, ctime, mtime, offset, size)
@@ -736,7 +764,7 @@ PackageDirectory::PackageDirectory(BFile *parent, const BString &path,
status_t status_t
PackageDirectory::DoInstall(const char *path, ItemState *state) PackageDirectory::DoInstall(const char* path, ItemState* state)
{ {
BPath &destination = state->destination; BPath &destination = state->destination;
status_t ret; status_t ret;
@@ -798,12 +826,12 @@ PackageFile::PackageFile(BFile *parent, const BString &path, uint8 type,
status_t status_t
PackageFile::DoInstall(const char *path, ItemState *state) PackageFile::DoInstall(const char* path, ItemState* state)
{ {
if (state == NULL) if (state == NULL)
return B_ERROR; return B_ERROR;
BPath &destination = state->destination; BPath& destination = state->destination;
status_t ret = B_OK; status_t ret = B_OK;
parser_debug("File: %s DoInstall() called!\n", fPath.String()); parser_debug("File: %s DoInstall() called!\n", fPath.String());
+14 -10
View File
@@ -85,7 +85,7 @@ public:
uint64 offset = 0, uint64 size = 0); uint64 offset = 0, uint64 size = 0);
virtual const uint32 ItemKind() {return P_NO_KIND;}; virtual const uint32 ItemKind() {return P_NO_KIND;};
protected: protected:
status_t InitPath(const char* path, BPath* destination); status_t InitPath(const char* path, BPath* destination);
status_t HandleAttributes(BPath* destination, BNode* node, status_t HandleAttributes(BPath* destination, BNode* node,
const char* header); const char* header);
@@ -97,11 +97,12 @@ public:
uint64* tempSize, uint64* attrCSize, uint64* tempSize, uint64* attrCSize,
uint64* attrOSize, bool* attrStarted, uint64* attrOSize, bool* attrStarted,
bool* done); bool* done);
status_t SkipAttribute(uint8 *buffer, bool *attrStarted, status_t SkipAttribute(uint8* buffer, bool* attrStarted,
bool *done); bool* done);
status_t ParseData(uint8* buffer, BFile* file, status_t ParseData(uint8* buffer, BFile* file,
uint64 originalSize, bool* done); uint64 originalSize, bool* done);
protected:
BString fPath; BString fPath;
uint64 fOffset; uint64 fOffset;
uint64 fSize; uint64 fSize;
@@ -120,15 +121,16 @@ public:
uint64 offset = 0, uint64 size = 0); uint64 offset = 0, uint64 size = 0);
virtual status_t DoInstall(const char* path = NULL, virtual status_t DoInstall(const char* path = NULL,
ItemState *state = NULL); ItemState* state = NULL);
virtual const uint32 ItemKind(); virtual const uint32 ItemKind();
}; };
class PackageScript : public PackageItem { class PackageScript : public PackageItem {
public: public:
PackageScript(BFile* parent, uint64 offset = 0, PackageScript(BFile* parent, const BString& path,
uint64 size = 0, uint64 originalSize = 0); uint64 offset = 0, uint64 size = 0,
uint64 originalSize = 0);
virtual status_t DoInstall(const char* path = NULL, virtual status_t DoInstall(const char* path = NULL,
ItemState *state = NULL); ItemState *state = NULL);
@@ -138,10 +140,12 @@ public:
void SetThreadId(thread_id id) { fThreadId = id; } void SetThreadId(thread_id id) { fThreadId = id; }
private: private:
status_t _ParseScript(uint8 *buffer, uint64 originalSize, status_t _ParseScript(uint8* buffer, uint64 originalSize,
bool *done); BString& script, bool* done);
status_t _RunScript(uint8 *script, uint32 len); status_t _RunScript(const char* workingDirectory,
const BString& script);
private:
uint64 fOriginalSize; uint64 fOriginalSize;
thread_id fThreadId; thread_id fThreadId;
}; };
@@ -156,7 +160,7 @@ public:
const BString& signature, uint32 mode); const BString& signature, uint32 mode);
virtual status_t DoInstall(const char* path = NULL, virtual status_t DoInstall(const char* path = NULL,
ItemState *state = NULL); ItemState* state = NULL);
virtual const uint32 ItemKind(); virtual const uint32 ItemKind();
private: private: