我有如下小程序:
#include <unistd.h>
#include <pwd.h>
#include <QCoreApplication>
#include <QDir>
const char * homeDir()
{
return getpwuid(geteuid())->pw_dir;
}
int main(int argc, char *argv[])
{
printf("Qt homedir: %s\n", qPrintable(QDir::homePath()));
printf("Native homedir: %s\n", homeDir());
QCoreApplication a(argc, argv);
return a.exec();
}
现在:
- 当“普通”用户直接运行
./program
时,输出为:Qt homedir: /home/user
Native homedir: /home/usr
没关系
- root直接运行
./program
时,输出为:Qt homedir: /root
Native homedir: /root
没关系
- 当由 root 作为不同的用户通过 sudo 运行时,例如
sudo -u user ./program
,输出为:Qt homedir: /home/user
Native homedir: /home/user
没关系
- 当通过 startproc 由 root 作为不同的用户运行时,例如
startproc -u user/full/path/to/program
,输出为:Qt homedir: /root
Native homedir: /home/user
这是不好的,或者不是预期的(至少对我而言)
我的问题是:为什么最后一次运行的结果与其他运行的结果不同?它是 Qt 中的一个错误(没有考虑到有效用户与真实用户不同的事实,或者不同的东西),还是我遗漏了一些背景信息(例如 startproc 的工作机制)?
有问题的 Qt 版本是 5.6.1。
最佳答案
Qt 的 QFileSystemEngine
在 Unix 上使用 HOME
环境变量的内容 - 请参阅其 implementation .然而 startproc -u
没有设置 HOME
:这就是它失败的原因。
getpwuid
调用可能非常昂贵并且可能会阻塞,即通过从 LDAP 或 AD 服务器等获取信息,最好由您自己处理。此外,它不是线程安全的,您应该改用 getpwuid_r
。
一个实现可能如下所示:
static QString getHomeDir() {
auto const N = sysconf(_SC_GETPW_R_SIZE_MAX);
auto *buffer = std::make_unique<char[]>(N);
passwd pwd;
passwd *result;
getpwuid_r(geteuid(), &pwd, buffer.get(), N, &result);
if (result) {
auto *dir = result->pw_dir;
auto const decoded = QFile::decodeName(dir);
return QDir::cleanPath(decoded);
}
return {};
}
enum class HomeDir { Default, Init };
QString homeDir(HomeDir option = HomeDir::Default) {
// needs a C++11 compiler for thread-safe initialization
static QFuture<QString> home = QtConcurrent::run(getHomeDir);
return (option == HomeDir::Init) ? QString() : home;
};
int main(int argc, char **argv) {
QCoreApplication app(argc, argv);
homeDir(HomeDir::Init);
// do other time-consuming initializations here
QString () << homeDir();
}
关于c++ - 对于由 startproc 运行的程序,QDir::homePath() 的非预期结果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49303486/