How can I get the actual \"username\" without using the environment (getenv, ...) in a program?
Today I had to do the same thing, but didn't like to include any OS specific headers. So here is what you can do in a cross-platform way without resorting to any Linux/Windows specific headers:
#include <stdio.h>
#include <memory>
#include <stdexcept>
#include <array>
#include <regex>
std::string execute_command(std::string cmd)
{
std::array<char, 128> buffer;
std::string result;
#if defined(_WIN32)
#define POPEN _popen
#define PCLOSE _pclose
#elif defined(unix) || defined(__unix__) || defined(__unix)
#define POPEN popen
#define PCLOSE pclose
#endif
std::unique_ptr<FILE, decltype(&PCLOSE)> pipe(POPEN(cmd.c_str(), "r"), PCLOSE);
if (!pipe)
{
throw std::runtime_error("popen() failed!");
}
while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr)
{
result += buffer.data();
}
return result;
}
std::string get_current_username()
{
#if defined(_WIN32)
#define USERNAME_QUERY "echo %USERNAME%" // whoami works on windows as well but it returns the name with the format `computer_name\user_name`
#elif defined(unix) || defined(__unix__) || defined(__unix)
#define USERNAME_QUERY "whoami"
#endif
auto username = execute_command(USERNAME_QUERY);
username = std::regex_replace(username, std::regex("\\s"), "");
return username;
}
This works just fine on both Linux and Windows and is C++11 compatible!
Test it online: https://onlinegdb.com/rk8T5LM9P
working a little bit through modern c++ specs
static auto whoAmI = [](){ struct passwd *tmp = getpwuid (geteuid ());
return tmp ? tmp->pw_name : "onlyGodKnows";
}
The function getlogin_r()
defined in unistd.h
returns the username. See man getlogin_r
for more information.
Its signature is:
int getlogin_r(char *buf, size_t bufsize);
Needless to say, this function can just as easily be called in C or C++.
Use char *cuserid(char *s)
found in stdio.h
.
#include <stdio.h>
#define MAX_USERID_LENGTH 32
int main()
{
char username[MAX_USERID_LENGTH];
cuserid(username);
printf("%s\n", username);
return 0;
}
See for more details:
From http://www.unix.com/programming/21041-getting-username-c-program-unix.html :
/* whoami.c */
#define _PROGRAM_NAME "whoami"
#include <stdlib.h>
#include <pwd.h>
#include <stdio.h>
int main(int argc, char *argv[])
{
register struct passwd *pw;
register uid_t uid;
int c;
uid = geteuid ();
pw = getpwuid (uid);
if (pw)
{
puts (pw->pw_name);
exit (EXIT_SUCCESS);
}
fprintf (stderr,"%s: cannot find username for UID %u\n",
_PROGRAM_NAME, (unsigned) uid);
exit (EXIT_FAILURE);
}
Just take main lines and encapsulate it in class:
class Env{
public:
static std::string getUserName()
{
uid_t uid = geteuid ();
struct passwd *pw = getpwuid (uid);
if (pw)
{
return std::string(pw->pw_name);
}
return {};
}
};
For C only:
const char *getUserName()
{
uid_t uid = geteuid();
struct passwd *pw = getpwuid(uid);
if (pw)
{
return pw->pw_name;
}
return "";
}