From 5c974e4e1ee5b140e9981301deea78497f85466d Mon Sep 17 00:00:00 2001 From: David Howells Date: Thu, 9 Jul 2020 11:27:04 +0100 Subject: [PATCH] Common display/formatting routines Add some common display and output formatting routines. Signed-off-by: David Howells --- kafs/Makefile | 2 + kafs/display.C | 169 +++++++++++++++++++++++++++++++++++++++++++++ kafs/display.H | 19 +++++ kafs/display_vol.C | 96 +++++++++++++++++++++++++ 4 files changed, 286 insertions(+) create mode 100644 kafs/display.C create mode 100644 kafs/display_vol.C diff --git a/kafs/Makefile b/kafs/Makefile index 28b9147..c673349 100644 --- a/kafs/Makefile +++ b/kafs/Makefile @@ -7,7 +7,9 @@ CORE_SRCS := \ kafs.C \ arg_completion.C \ arg_parse.C \ + display.C \ display_error.C \ + display_vol.C \ misc.C \ vl_fileservers.C \ vl_probe.C \ diff --git a/kafs/display.C b/kafs/display.C new file mode 100644 index 0000000..379b616 --- /dev/null +++ b/kafs/display.C @@ -0,0 +1,169 @@ +/* Display + * + * Copyright (C) 2020 Red Hat, Inc. All Rights Reserved. + * Written by David Howells (dhowells@redhat.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public Licence + * as published by the Free Software Foundation; either version + * 2 of the Licence, or (at your option) any later version. + */ + +#include +#include +#include +//#include +#include "kafs.H" +#include "vlservice.H" +#include "afs_xg.H" +#include "display.H" + +using rxrpc::ref; + +std::string kafs::sprint_time(const Time &time) +{ + return fmt::format("{:%a %b %d %H:%M:%S %Y}", fmt::localtime(time.seconds())); +} + +/** + * kafs::sprint_time_or_never - Print a time in standard format + * @time: The time to display. + * + * Print a time in a standard format for AFS tools to a string. If @time is 0, + * then "Never" will be printed instead. + */ +std::string kafs::sprint_time_or_never(const Time &time) +{ + if (time.seconds() == 0) + return "Never"; + else + return kafs::sprint_time(time); +} + +/** + * kafs::print_time - Print a time in standard format + * @time: The time to display. + * + * Print a time in a standard format for AFS tools to stdout. + */ +void kafs::print_time(const Time &time) +{ + time_t t = time.seconds(); + struct tm tm; + char buf[128]; + + localtime_r(&t, &tm); + strftime(buf, 128, "%a %b %d %H:%M:%S %Y", &tm); + std::cout << buf; +} + +/** + * kafs::print_time_or_never - Print a time in standard format + * @time: The time to display. + * + * Print a time in a standard format for AFS tools to stdout. If @time is 0, + * then "Never" will be printed instead. + */ +void kafs::print_time_or_never(const Time &time) +{ + if (time.seconds() == 0) + std::cout << "Never"; + else + kafs::print_time(time); +} + +/** + * kafs::sprint_address - Convert/resolve an address into text + * @ctx: The cell and authentication context + * @addr: The address to convert + * + * Convert an address into a textual representation, possibly resolving it to a + * hostname via the DNS or other name resolution service. The conversion is + * written into the buffer and truncated to the length given. + */ +std::string kafs::sprint_address(Context *ctx, + const struct sockaddr_rxrpc &addr) +{ + unsigned short port; + char buf[1024], service[64], *b; + size_t len; + int hint, ni; + + hint = NI_DGRAM | NI_NUMERICSERV; + + if (!ctx->no_resolve) { + hint |= NI_NAMEREQD; + ni = getnameinfo((struct sockaddr *)&addr.transport, + addr.transport_len, + buf, sizeof(buf), service, sizeof(service), hint); + if (ni == EAI_MEMORY) + throw rxrpc::nomem(); + if (ni == 0) + return fmt::format("{}:{}", buf, service); + } + + hint &= ~NI_NAMEREQD; + hint |= NI_NUMERICHOST; + b = buf + 1; + ni = getnameinfo((struct sockaddr *)&addr.transport, + addr.transport_len, + b, sizeof(buf) - 2, service, sizeof(service), hint); + if (ni == EAI_MEMORY) + throw rxrpc::nomem(); + + if (strchr(b, ':')) { + len = strlen(b); + b[-1] = '['; + b[len] = ']'; + b[len + 1] = 0; + b--; + } + + if (ni == 0) + return fmt::format("{}:{}", b, service); + + buf[0] = 0; + switch (addr.transport.sin.sin_family) { + case AF_INET: + inet_ntop(AF_INET, &addr.transport.sin.sin_addr, buf, sizeof(buf)); + port = ntohs(addr.transport.sin.sin_port); + break; + case AF_INET6: + buf[0] = '['; + inet_ntop(AF_INET6, &addr.transport.sin6.sin6_addr, buf + 1, sizeof(buf) - 2); + len = strlen(buf); + buf[len] = ']'; + buf[len + 1] = 0; + port = ntohs(addr.transport.sin6.sin6_port); + break; + default: + return fmt::format("", addr.transport.sin.sin_family); + } + + if (port == afs::FS_PORT) + return std::string(buf); + + return fmt::format("{}+{:d}", b, port); +} + +/* + * kafs::sprint_address - Convert a numeric ID into a partition name string. + * @ctx: The cell and authentication context + * @partition: The partition specified to convert + * + * Render the numeric partition ID to the standard string representation and + * write it into the buffer. + */ +std::string kafs::sprint_partition(const Partition_spec &partition) +{ + unsigned int n = partition.id; + + if (n < 26) { + return fmt::format("/vicep{:c}", (char)(n + 97)); + } else if (n <= 255) { + n -= 26; + return fmt::format("/vicep{:c}{:c}", (char)(n / 26 + 97), (char)(n % 26 + 97)); + } else { + return fmt::format("/vicep?{:d}", n); + } +} diff --git a/kafs/display.H b/kafs/display.H index 26c0fdf..e76b9af 100644 --- a/kafs/display.H +++ b/kafs/display.H @@ -16,11 +16,30 @@ namespace kafs { +struct Vldb_entry; +struct Vldb_site; + +/* + * display.C + */ +extern std::string sprint_time(const Time &); +extern std::string sprint_time_or_never(const Time &); +extern void print_time(const Time &); +extern void print_time_or_never(const Time &); +extern std::string sprint_address(Context *, const struct sockaddr_rxrpc &); +extern std::string sprint_partition(const Partition_spec &); + /* * display_error.C */ extern bool kafs_display_error(Context *); +/* + * display_vol.C + */ +extern std::string sprint_site(Context *, Vldb_site &); +extern void display_vldb_site_list(Context *, Vldb_entry *, const char *); + } /* end namespace kafs */ #endif /* DISPLAY_H */ diff --git a/kafs/display_vol.C b/kafs/display_vol.C new file mode 100644 index 0000000..d38c059 --- /dev/null +++ b/kafs/display_vol.C @@ -0,0 +1,96 @@ +/* Volume information display. + * + * Copyright (C) 2020 Red Hat, Inc. All Rights Reserved. + * Written by David Howells (dhowells@redhat.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public Licence + * as published by the Free Software Foundation; either version + * 2 of the Licence, or (at your option) any later version. + */ + +#include +#include +#include "kafs.H" +#include "vlservice.H" +#include "afs_xg.H" +#include "display.H" + +using rxrpc::ref; + +/* + * Convert a volume site into a textual representation, possibly resolving it + * to a DNS hostname. + */ +std::string kafs::sprint_site(Context *ctx, Vldb_site &vldb_site) +{ + FS_site *site = vldb_site.fs_site; + + if (!site) + return ""; + + std::vector &addrs = site->vs_addrs; + + if (!addrs.size()) { + if (vldb_site.has_uuid) { + char buf[48]; + uuid_unparse(vldb_site.uuid.uuid, buf); + return std::string(buf); + } + return ""; + } + + return sprint_address(ctx, addrs[0]); +} + +/* + * Display the VLDB site list, looking something like: + * + * number of sites -> 2 + * server fserver.abc.com partition /vicepa RW Site + * server fserver.abc.com partition /vicepa RO Site + */ +void kafs::display_vldb_site_list(Context *ctx, + Vldb_entry *vldb, + const char *indent) +{ + const char *ptype; + unsigned int i; + + std::cout << indent << "number of sites -> " << vldb->sites.size() << "\n"; + for (i = 0; i < vldb->sites.size(); i++) { + Vldb_site &site = vldb->sites[i]; + unsigned int flags = site.flags; + + if (flags & afs::VLSF_ROVOL) + ptype = "RO"; + else if (flags & afs::VLSF_RWVOL) + ptype = "RW"; + else + ptype = "Back"; + + std::cout << indent + << " server " << sprint_site(ctx, site) + << " partition " << sprint_partition(site.partition) + << " " << ptype << " Site\n"; + } + + if (vldb->flags & (afs::VLOP_MOVE | + afs::VLOP_RELEASE | + afs::VLOP_BACKUP | + afs::VLOP_DELETE | + afs::VLOP_DUMP) + ) { + std::cout << indent << "Volume is currently LOCKED\n"; + if (vldb->flags & afs::VLOP_MOVE) + std::cout << indent << "Volume is locked for a move operation\n"; + if (vldb->flags & afs::VLOP_RELEASE) + std::cout << indent << "Volume is locked for a release operation\n"; + if (vldb->flags & afs::VLOP_BACKUP) + std::cout << indent << "Volume is locked for a backup operation\n"; + if (vldb->flags & afs::VLOP_DELETE) + std::cout << indent << "Volume is locked for a delete/misc operation\n"; + if (vldb->flags & afs::VLOP_DUMP) + std::cout << indent << "Volume is locked for a dump/restore operation\n"; + } +} -- 2.49.0