summaryrefslogtreecommitdiff
path: root/zen/sys_info.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'zen/sys_info.cpp')
-rw-r--r--zen/sys_info.cpp85
1 files changed, 54 insertions, 31 deletions
diff --git a/zen/sys_info.cpp b/zen/sys_info.cpp
index d208cc98..bc1bfe62 100644
--- a/zen/sys_info.cpp
+++ b/zen/sys_info.cpp
@@ -28,30 +28,32 @@ Zstring zen::getLoginUser() //throw FileError
{
auto tryGetNonRootUser = [](const char* varName) -> const char*
{
- if (const char* buf = ::getenv(varName)) //no extended error reporting
+ if (const char* buf = ::getenv(varName)) //no ownership transfer + no extended error reporting
if (strLength(buf) > 0 && !equalString(buf, "root"))
return buf;
return nullptr;
};
- const uid_t userIdNo = ::getuid(); //never fails
-
- if (userIdNo != 0) //nofail; non-root
+ if (const uid_t userIdNo = ::getuid(); //never fails
+ userIdNo != 0) //nofail; non-root
{
- std::vector<char> buf(std::max<long>(10000, ::sysconf(_SC_GETPW_R_SIZE_MAX))); //::sysconf may return long(-1)
+ //ugh, the world's stupidest API:
+ std::vector<char> buf(std::max<long>(10000, ::sysconf(_SC_GETPW_R_SIZE_MAX))); //::sysconf may return long(-1) or even a too small size!! WTF!
passwd buf2 = {};
- passwd* pwsEntry = nullptr;
- if (::getpwuid_r(userIdNo, //uid_t uid
- &buf2, //struct passwd* pwd
- &buf[0], //char* buf
- buf.size(), //size_t buflen
- &pwsEntry) != 0) //struct passwd** result
- THROW_LAST_FILE_ERROR(_("Cannot get process information."), "getpwuid_r");
-
- if (!pwsEntry)
- throw FileError(_("Cannot get process information."), L"no login found"); //should not happen?
-
- return pwsEntry->pw_name;
+ passwd* pwEntry = nullptr;
+ if (const int rv = ::getpwuid_r(userIdNo, //uid_t uid
+ &buf2, //struct passwd* pwd
+ &buf[0], //char* buf
+ buf.size(), //size_t buflen
+ &pwEntry); //struct passwd** result
+ rv != 0 || !pwEntry)
+ {
+ //"If an error occurs, errno is set appropriately" => why the fuck, then also return errno as return value!?
+ errno = rv != 0 ? rv : ENOENT;
+ THROW_LAST_FILE_ERROR(_("Cannot get process information."), "getpwuid_r(" + numberTo<std::string>(userIdNo) + ')');
+ }
+
+ return pwEntry->pw_name;
}
//else: root(0) => consider as request for elevation, NOT impersonation!
@@ -178,29 +180,49 @@ Zstring zen::getRealProcessPath() //throw FileError
}
-namespace
-{
-Zstring getUserDir() //throw FileError
+Zstring zen::getUserHome() //throw FileError
{
+ if (::getuid() != 0) //nofail; non-root
+ /* https://linux.die.net/man/3/getpwuid: An application that wants to determine its user's home directory
+ should inspect the value of HOME (rather than the value getpwuid(getuid())->pw_dir) since this allows
+ the user to modify their notion of "the home directory" during a login session. */
+ if (const char* homePath = ::getenv("HOME")) //no ownership transfer + no extended error reporting
+ return homePath;
+
+ //root(0) => consider as request for elevation, NOT impersonation!
+ //=> no support for HOME variable :(
+
const Zstring loginUser = getLoginUser(); //throw FileError
- if (loginUser == "root")
- return "/root";
- else
- return "/home/" + loginUser;
- //safer? sudo --user $userName sh -c 'echo $HOME'
-}
+ //ugh, the world's stupidest API:
+ std::vector<char> buf(std::max<long>(10000, ::sysconf(_SC_GETPW_R_SIZE_MAX))); //::sysconf may return long(-1) or even a too small size!! WTF!
+ passwd buf2 = {};
+ passwd* pwEntry = nullptr;
+ if (const int rv = ::getpwnam_r(loginUser.c_str(), //const char *name
+ &buf2, //struct passwd* pwd
+ &buf[0], //char* buf
+ buf.size(), //size_t buflen
+ &pwEntry); //struct passwd** result
+ rv != 0 || !pwEntry)
+ {
+ //"If an error occurs, errno is set appropriately" => why the fuck, then also return errno as return value!?
+ errno = rv != 0 ? rv : ENOENT;
+ THROW_LAST_FILE_ERROR(_("Cannot get process information."), "getpwnam_r(" + utfTo<std::string>(loginUser) + ')');
+ }
+
+ return pwEntry->pw_dir; //home directory
}
Zstring zen::getUserDataPath() //throw FileError
{
- if (::getuid() != 0) //nofail; root(0) => consider as request for elevation, NOT impersonation
- if (const char* xdgCfgPath = ::getenv("XDG_CONFIG_HOME"); //no extended error reporting
+ if (::getuid() != 0) //nofail; non-root
+ if (const char* xdgCfgPath = ::getenv("XDG_CONFIG_HOME"); //no ownership transfer + no extended error reporting
xdgCfgPath && xdgCfgPath[0] != 0)
return xdgCfgPath;
+ //root(0) => consider as request for elevation, NOT impersonation
- return getUserDir() + "/.config"; //throw FileError
+ return appendPath(getUserHome(), ".config"); //throw FileError
}
@@ -208,7 +230,7 @@ Zstring zen::getUserDownloadsPath() //throw FileError
{
try
{
- if (::getuid() != 0) //nofail; root(0) => consider as request for elevation, NOT impersonation
+ if (::getuid() != 0) //nofail; non-root
if (const auto& [exitCode, output] = consoleExecute("xdg-user-dir DOWNLOAD", std::nullopt /*timeoutMs*/); //throw SysError
exitCode == 0)
{
@@ -216,9 +238,10 @@ Zstring zen::getUserDownloadsPath() //throw FileError
ASSERT_SYSERROR(!downloadsPath.empty());
return downloadsPath;
}
+ //root(0) => consider as request for elevation, NOT impersonation
//fallback: probably correct 99.9% of the time anyway...
- return getUserDir() + "/Downloads"; //throw FileError
+ return appendPath(getUserHome(), "Downloads"); //throw FileError
}
catch (const SysError& e) { throw FileError(_("Cannot get process information."), e.toString()); }
}
bgstack15