diff options
Diffstat (limited to 'usr.sbin/pmcstat/pmcstat_log.c')
-rw-r--r-- | usr.sbin/pmcstat/pmcstat_log.c | 73 |
1 files changed, 67 insertions, 6 deletions
diff --git a/usr.sbin/pmcstat/pmcstat_log.c b/usr.sbin/pmcstat/pmcstat_log.c index 8cf3087..0beb7c7 100644 --- a/usr.sbin/pmcstat/pmcstat_log.c +++ b/usr.sbin/pmcstat/pmcstat_log.c @@ -40,6 +40,7 @@ __FBSDID("$FreeBSD$"); #include <sys/mman.h> #include <sys/pmc.h> #include <sys/queue.h> +#include <sys/socket.h> #include <sys/stat.h> #include <sys/wait.h> @@ -47,9 +48,11 @@ __FBSDID("$FreeBSD$"); #include <assert.h> #include <err.h> +#include <errno.h> #include <fcntl.h> #include <libgen.h> #include <limits.h> +#include <netdb.h> #include <pmc.h> #include <pmclog.h> #include <sysexits.h> @@ -1639,19 +1642,77 @@ pmcstat_close_log(struct pmcstat_args *a) int pmcstat_open_log(const char *path, int mode) { - int fd; + int error, fd; + size_t hlen; + const char *p, *errstr; + struct addrinfo hints, *res, *res0; + char hostname[MAXHOSTNAMELEN]; + + errstr = NULL; + fd = -1; /* * If 'path' is "-" then open one of stdin or stdout depending - * on the value of 'mode'. Otherwise, treat 'path' as a file - * name and open that. + * on the value of 'mode'. + * + * If 'path' contains a ':' and does not start with a '/' or '.', + * and is being opened for writing, treat it as a "host:port" + * specification and open a network socket. + * + * Otherwise, treat 'path' as a file name and open that. */ if (path[0] == '-' && path[1] == '\0') fd = (mode == PMCSTAT_OPEN_FOR_READ) ? 0 : 1; - else - fd = open(path, mode == PMCSTAT_OPEN_FOR_READ ? + else if (mode == PMCSTAT_OPEN_FOR_WRITE && path[0] != '/' && + path[0] != '.' && strchr(path, ':') != NULL) { + + p = strrchr(path, ':'); + hlen = p - path; + if (p == path || hlen >= sizeof(hostname)) { + errstr = strerror(EINVAL); + goto done; + } + + assert(hlen < sizeof(hostname)); + (void) strncpy(hostname, path, hlen); + hostname[hlen] = '\0'; + + (void) memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + if ((error = getaddrinfo(hostname, p+1, &hints, &res0)) != 0) { + errstr = gai_strerror(error); + goto done; + } + + fd = -1; + for (res = res0; res; res = res->ai_next) { + if ((fd = socket(res->ai_family, res->ai_socktype, + res->ai_protocol)) < 0) { + errstr = strerror(errno); + continue; + } + if (connect(fd, res->ai_addr, res->ai_addrlen) < 0) { + errstr = strerror(errno); + (void) close(fd); + fd = -1; + continue; + } + errstr = NULL; + break; + } + freeaddrinfo(res0); + + } else if ((fd = open(path, mode == PMCSTAT_OPEN_FOR_READ ? O_RDONLY : (O_WRONLY|O_CREAT|O_TRUNC), - S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH); + S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)) < 0) + errstr = strerror(errno); + + done: + if (errstr) + errx(EX_OSERR, "ERROR: Cannot open \"%s\" for %s: %s.", path, + (mode == PMCSTAT_OPEN_FOR_READ ? "reading" : "writing"), + errstr); return (fd); } |