aboutsummaryrefslogtreecommitdiff
path: root/qga/commands-posix.c
diff options
context:
space:
mode:
authorStefan Hajnoczi <stefanha@redhat.com>2017-04-28 16:12:11 +0100
committerStefan Hajnoczi <stefanha@redhat.com>2017-04-28 16:12:19 +0100
commit7ad691ec988dd0ca1c3674018f6aede8ed18128b (patch)
tree9ea5883ab18b0a0e4389875840057519bb364e1e /qga/commands-posix.c
parent81b2d5ceb0cfb4cdc2163492e3169ed714b0cda9 (diff)
parent53c58e64d0a27c59d763778faa2b5a522c544719 (diff)
Merge remote-tracking branch 'mdroth/tags/qga-pull-2017-04-25-v2-tag' into staging
qemu-ga patch queue * new commands: guest-get-timezone, guest-get-users, guest-get-host-name * fix hang on w32 when stopping qemu-ga service while fs frozen * fix missing setting of can-offline in guest-get-vcpus * make qemu-ga VSS w32 service on-demand rather than on-startup * fix unecessary errors to EventLog on w32 * improvements to fsfreeze documentation v2: * document 'zone' field of guest-get-timezone as informational-only (Daniel, Eric) * fix build error for glib < 2.32 (Peter) # gpg: Signature made Thu 27 Apr 2017 06:43:42 AM BST # gpg: using RSA key 0x3353C9CEF108B584 # gpg: Good signature from "Michael Roth <flukshun@gmail.com>" # gpg: aka "Michael Roth <mdroth@utexas.edu>" # gpg: aka "Michael Roth <mdroth@linux.vnet.ibm.com>" # Primary key fingerprint: CEAC C9E1 5534 EBAB B82D 3FA0 3353 C9CE F108 B584 * mdroth/tags/qga-pull-2017-04-25-v2-tag: qga: Add `guest-get-timezone` command qga: Add 'guest-get-users' command qga: improve fsfreeze documentations qga: Add 'guest-get-host-name' command qga-win: Fix Event Viewer errors caused by qemu-ga qga-win: Fix a bug where qemu-ga service is stuck during stop operation qga-win: Enable 'can-offline' field in 'guest-get-vcpus' reply qemu-ga: Make QGA VSS provider service run only when needed Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
Diffstat (limited to 'qga/commands-posix.c')
-rw-r--r--qga/commands-posix.c60
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;
+}