dovecot-2.0-sslstream: doveadm: Added "who" command to list conn...
dovecot at dovecot.org
dovecot at dovecot.org
Sat Feb 13 02:55:27 EET 2010
details: http://hg.dovecot.org/dovecot-2.0-sslstream/rev/b8df77326978
changeset: 10147:b8df77326978
user: Timo Sirainen <tss at iki.fi>
date: Thu Oct 22 20:32:55 2009 -0400
description:
doveadm: Added "who" command to list connected users based on anvil information.
diffstat:
4 files changed, 234 insertions(+), 1 deletion(-)
src/doveadm/Makefile.am | 3
src/doveadm/doveadm-who.c | 230 +++++++++++++++++++++++++++++++++++++++++++++
src/doveadm/doveadm.c | 1
src/doveadm/doveadm.h | 1
diffs (269 lines):
diff -r 1110edddec36 -r b8df77326978 src/doveadm/Makefile.am
--- a/src/doveadm/Makefile.am Thu Oct 22 20:28:46 2009 -0400
+++ b/src/doveadm/Makefile.am Thu Oct 22 20:32:55 2009 -0400
@@ -36,7 +36,8 @@ doveadm_SOURCES = \
doveadm-dump-mailboxlog.c \
doveadm-dump-thread.c \
doveadm-mail.c \
- doveadm-pw.c
+ doveadm-pw.c \
+ doveadm-who.c
noinst_HEADERS = \
doveadm.h \
diff -r 1110edddec36 -r b8df77326978 src/doveadm/doveadm-who.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/doveadm/doveadm-who.c Thu Oct 22 20:32:55 2009 -0400
@@ -0,0 +1,230 @@
+/* Copyright (c) 2009 Dovecot authors, see the included COPYING file */
+
+#include "lib.h"
+#include "array.h"
+#include "network.h"
+#include "istream.h"
+#include "hash.h"
+#include "doveadm.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+struct who_user {
+ const char *username;
+ ARRAY_DEFINE(ips, struct ip_addr);
+ ARRAY_DEFINE(pids, pid_t);
+ unsigned int connection_count;
+};
+
+struct who_filter {
+ const char *username;
+ struct ip_addr net_ip;
+ unsigned int net_bits;
+};
+
+struct who_context {
+ const char *anvil_path;
+ struct who_filter filter;
+
+ pool_t pool;
+ struct hash_table *users; /* username -> who_user */
+};
+
+static bool
+who_user_has_ip(const struct who_user *user, const struct ip_addr *ip)
+{
+ const struct ip_addr *ex_ip;
+
+ array_foreach(&user->ips, ex_ip) {
+ if (net_ip_compare(ex_ip, ip))
+ return TRUE;
+ }
+ return FALSE;
+}
+
+static void who_line(struct who_context *ctx,
+ const char *const *args)
+{
+ const char *ident = args[0];
+ pid_t pid = strtoul(args[1], NULL, 10);
+ unsigned int refcount = atoi(args[2]);
+ const char *p, *service, *ip_str, *username;
+ struct who_user *user;
+ struct ip_addr ip;
+ const pid_t *ex_pid;
+ char *username_dup;
+
+ p = strchr(ident, '/');
+ service = t_strdup_until(ident, p++);
+ username = strchr(p, '/');
+ ip_str = t_strdup_until(p, username++);
+ if (net_addr2ip(ip_str, &ip) < 0)
+ memset(&ip, 0, sizeof(ip));
+
+ user = hash_table_lookup(ctx->users, username);
+ if (user == NULL) {
+ user = p_new(ctx->pool, struct who_user, 1);
+ username_dup = p_strdup(ctx->pool, username);
+ user->username = username_dup;
+ p_array_init(&user->ips, ctx->pool, 3);
+ p_array_init(&user->pids, ctx->pool, 8);
+ hash_table_insert(ctx->users, username_dup, user);
+ }
+ user->connection_count += refcount;
+
+ if (ip.family != 0 && !who_user_has_ip(user, &ip))
+ array_append(&user->ips, &ip, 1);
+
+ array_foreach(&user->pids, ex_pid) {
+ if (*ex_pid == pid)
+ break;
+ }
+ if (*ex_pid != pid)
+ array_append(&user->pids, &pid, 1);
+}
+
+static void who_lookup(struct who_context *ctx)
+{
+#define ANVIL_HANDSHAKE "VERSION\tanvil\t1\t0\n"
+#define ANVIL_CMD ANVIL_HANDSHAKE"CONNECT-DUMP\n"
+ struct istream *input;
+ const char *line;
+ int fd;
+
+ fd = net_connect_unix(ctx->anvil_path);
+ if (fd == -1)
+ i_fatal("net_connect_unix(%s) failed: %m", ctx->anvil_path);
+ net_set_nonblock(fd, FALSE);
+
+ input = i_stream_create_fd(fd, (size_t)-1, TRUE);
+ if (write(fd, ANVIL_CMD, strlen(ANVIL_CMD)) < 0)
+ i_fatal("write(%s) failed: %m", ctx->anvil_path);
+ while ((line = i_stream_read_next_line(input)) != NULL) {
+ if (*line == '\0')
+ break;
+ T_BEGIN {
+ who_line(ctx, t_strsplit(line, "\t"));
+ } T_END;
+ }
+ if (input->stream_errno != 0)
+ i_fatal("read(%s) failed: %m", ctx->anvil_path);
+
+ i_stream_destroy(&input);
+}
+
+static bool who_filter_match(const struct who_user *user,
+ const struct who_filter *filter)
+{
+ if (filter->username != NULL) {
+ if (strstr(user->username, filter->username) == NULL)
+ return FALSE;
+ }
+ if (filter->net_bits > 0) {
+ const struct ip_addr *ip;
+ bool ret = FALSE;
+
+ array_foreach(&user->ips, ip) {
+ if (net_is_in_network(ip, &filter->net_ip,
+ filter->net_bits)) {
+ ret = TRUE;
+ break;
+ }
+ }
+ if (!ret)
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static void who_print(struct who_context *ctx)
+{
+ struct hash_iterate_context *iter;
+ void *key, *value;
+
+ fprintf(stderr, "%-30s # (ips) (pids)\n", "username");
+
+ iter = hash_table_iterate_init(ctx->users);
+ while (hash_table_iterate(iter, &key, &value)) {
+ struct who_user *user = value;
+ const struct ip_addr *ip;
+ const pid_t *pid;
+ bool first = TRUE;
+
+ if (!who_filter_match(user, &ctx->filter))
+ continue;
+
+ printf("%-30s %2u ", user->username, user->connection_count);
+
+ printf("(");
+ array_foreach(&user->ips, ip) T_BEGIN {
+ if (first)
+ first = FALSE;
+ else
+ printf(" ");
+ printf("%s", net_ip2addr(ip));
+ } T_END;
+ printf(") (");
+ first = TRUE;
+ array_foreach(&user->pids, pid) T_BEGIN {
+ if (first)
+ first = FALSE;
+ else
+ printf(" ");
+ printf("%ld", (long)*pid);
+ } T_END;
+ printf(")\n");
+ };
+ hash_table_iterate_deinit(&iter);
+}
+
+static void cmd_who(int argc, char *argv[])
+{
+ struct who_context ctx;
+ struct ip_addr net_ip;
+ unsigned int net_bits;
+ int c;
+
+ memset(&ctx, 0, sizeof(ctx));
+ ctx.anvil_path = PKG_RUNDIR"/anvil";
+ ctx.pool = pool_alloconly_create("who users", 10240);
+ ctx.users = hash_table_create(default_pool, ctx.pool, 0, str_hash,
+ (hash_cmp_callback_t *)strcmp);
+
+ while ((c = getopt(argc, argv, "a:")) > 0) {
+ switch (c) {
+ case 'a':
+ ctx.anvil_path = optarg;
+ break;
+ default:
+ help(&doveadm_cmd_who);
+ }
+ }
+
+ argv += optind - 1;
+ while (argv[1] != NULL) {
+ if (net_parse_range(argv[1], &net_ip, &net_bits) == 0) {
+ if (ctx.filter.net_bits != 0)
+ usage();
+ ctx.filter.net_ip = net_ip;
+ ctx.filter.net_bits = net_bits;
+ } else {
+ if (ctx.filter.username != NULL)
+ usage();
+ ctx.filter.username = argv[1];
+ }
+ argv++;
+ }
+
+ who_lookup(&ctx);
+ who_print(&ctx);
+
+ hash_table_destroy(&ctx.users);
+ pool_unref(&ctx.pool);
+}
+
+struct doveadm_cmd doveadm_cmd_who = {
+ cmd_who, "who",
+ "[-a <anvil socket path>] [<user>] [<ip/bits>]", NULL
+};
diff -r 1110edddec36 -r b8df77326978 src/doveadm/doveadm.c
--- a/src/doveadm/doveadm.c Thu Oct 22 20:28:46 2009 -0400
+++ b/src/doveadm/doveadm.c Thu Oct 22 20:32:55 2009 -0400
@@ -82,6 +82,7 @@ int main(int argc, char *argv[])
doveadm_register_cmd(&doveadm_cmd_user);
doveadm_register_cmd(&doveadm_cmd_dump);
doveadm_register_cmd(&doveadm_cmd_pw);
+ doveadm_register_cmd(&doveadm_cmd_who);
/* "+" is GNU extension to stop at the first non-option.
others just accept -+ option. */
diff -r 1110edddec36 -r b8df77326978 src/doveadm/doveadm.h
--- a/src/doveadm/doveadm.h Thu Oct 22 20:28:46 2009 -0400
+++ b/src/doveadm/doveadm.h Thu Oct 22 20:32:55 2009 -0400
@@ -16,6 +16,7 @@ extern struct doveadm_cmd doveadm_cmd_us
extern struct doveadm_cmd doveadm_cmd_user;
extern struct doveadm_cmd doveadm_cmd_dump;
extern struct doveadm_cmd doveadm_cmd_pw;
+extern struct doveadm_cmd doveadm_cmd_who;
void doveadm_register_cmd(const struct doveadm_cmd *cmd);
More information about the dovecot-cvs
mailing list