streamlets: fix command name collisions, do not prepend $RELPIPE_IN_FILESYSTEM_STREAMLET_PATH to the $PATH v_0
authorFrantišek Kučera <franta-hg@frantovo.cz>
Sun, 19 Jan 2020 00:57:22 +0100
branchv_0
changeset 46 b5ae61996281
parent 45 f466b4c7d9b1
child 47 beefddde951e
streamlets: fix command name collisions, do not prepend $RELPIPE_IN_FILESYSTEM_STREAMLET_PATH to the $PATH (a streamlet may call a command with the same name as the streamlet name, which will lead unwanted recursion)
src/StreamletAttributeFinder.h
src/SubProcess.cpp
--- a/src/StreamletAttributeFinder.h	Sat Jan 18 20:09:34 2020 +0100
+++ b/src/StreamletAttributeFinder.h	Sun Jan 19 00:57:22 2020 +0100
@@ -20,6 +20,7 @@
 #include <filesystem>
 #include <regex>
 #include <memory>
+#include <sstream>
 
 #include <relpipe/writer/typedefs.h>
 #include <relpipe/writer/AttributeMetadata.h>
@@ -43,15 +44,31 @@
 	std::map<int, std::shared_ptr<SubProcess>> subProcesses;
 	std::map<int, std::vector<AttributeMetadata>> cachedMetadata;
 
-	string_t getStreamletPath() {
-		const char* originalPath = getenv("PATH");
-		const char* streamletPath = getenv("RELPIPE_IN_FILESYSTEM_STREAMLET_PATH");
+	string_t getStreamletCommand(const RequestedField& field) {
+		const char* streamletPathChars = getenv("RELPIPE_IN_FILESYSTEM_STREAMLET_PATH");
+		if (streamletPathChars) {
+			std::wstringstream current;
+			string_t streamletPath = convertor.from_bytes(streamletPathChars);
+			for (int i = 0, streamletPathSize = streamletPath.size(); i < streamletPathSize; i++) {
+				if (streamletPath[i] == ':' || i == streamletPathSize - 1) { // FIXME: support \: and \\ escaping
+					current << L"/" << field.name;
+					fs::path streamletFile(current.str());
+					if (fs::exists(streamletFile)) { // FIXME: check executable bit
+						return current.str();
+					} else {
+						current.str(L"");
+						current.clear();
+					}
+				} else {
+					current.put(streamletPath[i]);
+				}
+			}
+			throw RelpipeWriterException(L"Streamlet „" + field.name + L"“ was not found at $RELPIPE_IN_FILESYSTEM_STREAMLET_PATH");
+		} else {
+			throw RelpipeWriterException(L"Missing environment variable RELPIPE_IN_FILESYSTEM_STREAMLET_PATH → unable to find streamlet.");
+		}
+	}
 
-		if (originalPath && streamletPath) return convertor.from_bytes(std::string(streamletPath) + ":" + originalPath);
-		else if (originalPath) return convertor.from_bytes(std::string(originalPath));
-		else if (streamletPath) return convertor.from_bytes(std::string(streamletPath));
-		else return L"";
-	}
 protected:
 
 	void startFile(const fs::path& file, const string& fileRaw, bool exists) override {
@@ -90,7 +107,7 @@
 				return cachedMetadata[field.id];
 			} else {
 
-				std::vector<string_t> commandLine = {field.name};
+				std::vector<string_t> commandLine = {getStreamletCommand(field)};
 				std::map<string_t, string_t> environment;
 
 				for (auto mn : StreamletMsg::getMessageNames()) {
@@ -98,8 +115,6 @@
 					environment[L"EXEC_MSG_" + std::to_wstring(mn.first)] = mn.second;
 				}
 
-				environment[L"PATH"] = getStreamletPath();
-
 				shared_ptr<SubProcess> subProcess(SubProcess::create(commandLine, environment));
 				subProcesses[field.id] = subProcess;
 
--- a/src/SubProcess.cpp	Sat Jan 18 20:09:34 2020 +0100
+++ b/src/SubProcess.cpp	Sun Jan 19 00:57:22 2020 +0100
@@ -76,7 +76,7 @@
 		for (size_t i = 0; i < args.size(); i++) a[i] = args[i].c_str();
 		a[args.size()] = nullptr;
 
-		execvp(a[0], (char*const*) a);
+		execv(a[0], (char*const*) a);
 
 		delete[] a;
 		throw SubProcess::Exception(L"Unable to do execvp().");