diff options
Diffstat (limited to 'qga/commands-posix.c')
-rw-r--r-- | qga/commands-posix.c | 60 |
1 files changed, 60 insertions, 0 deletions
diff --git a/qga/commands-posix.c b/qga/commands-posix.c index 915df9ed90..ba06be4c86 100644 --- a/qga/commands-posix.c +++ b/qga/commands-posix.c @@ -15,6 +15,7 @@ #include <sys/ioctl.h> #include <sys/wait.h> #include <dirent.h> +#include <utmpx.h> #include "qga/guest-agent-core.h" #include "qga-qmp-commands.h" #include "qapi/qmp/qerror.h" @@ -2517,3 +2518,62 @@ void ga_command_state_init(GAState *s, GACommandState *cs) ga_command_state_add(cs, NULL, guest_fsfreeze_cleanup); #endif } + +#define QGA_MICRO_SECOND_TO_SECOND 1000000 + +static double ga_get_login_time(struct utmpx *user_info) +{ + double seconds = (double)user_info->ut_tv.tv_sec; + double useconds = (double)user_info->ut_tv.tv_usec; + useconds /= QGA_MICRO_SECOND_TO_SECOND; + return seconds + useconds; +} + +GuestUserList *qmp_guest_get_users(Error **err) +{ + GHashTable *cache = NULL; + GuestUserList *head = NULL, *cur_item = NULL; + struct utmpx *user_info = NULL; + gpointer value = NULL; + GuestUser *user = NULL; + GuestUserList *item = NULL; + double login_time = 0; + + cache = g_hash_table_new(g_str_hash, g_str_equal); + setutxent(); + + for (;;) { + user_info = getutxent(); + if (user_info == NULL) { + break; + } else if (user_info->ut_type != USER_PROCESS) { + continue; + } else if (g_hash_table_contains(cache, user_info->ut_user)) { + value = g_hash_table_lookup(cache, user_info->ut_user); + user = (GuestUser *)value; + login_time = ga_get_login_time(user_info); + /* We're ensuring the earliest login time to be sent */ + if (login_time < user->login_time) { + user->login_time = login_time; + } + continue; + } + + item = g_new0(GuestUserList, 1); + item->value = g_new0(GuestUser, 1); + item->value->user = g_strdup(user_info->ut_user); + item->value->login_time = ga_get_login_time(user_info); + + g_hash_table_insert(cache, item->value->user, item->value); + + if (!cur_item) { + head = cur_item = item; + } else { + cur_item->next = item; + cur_item = item; + } + } + endutxent(); + g_hash_table_destroy(cache); + return head; +} |