aboutsummaryrefslogtreecommitdiff
path: root/usr.bin/logger/logger.c
diff options
context:
space:
mode:
authorHiroki Sato <hrs@FreeBSD.org>2016-12-22 23:39:11 +0000
committerHiroki Sato <hrs@FreeBSD.org>2016-12-22 23:39:11 +0000
commita04667ab172598d17ccf33d73ba13f427982527a (patch)
treeb590a4c30abfbef1bf2c1afe618c01ed86d52878 /usr.bin/logger/logger.c
parent7c39dd2e165c26b81c6238275f7b01a5d396f8b8 (diff)
downloadsrc-a04667ab172598d17ccf33d73ba13f427982527a.tar.gz
src-a04667ab172598d17ccf33d73ba13f427982527a.zip
- Add -S option to specify the source address/port for UDP communication.
- Document -S option. - Document that -h option supports AF_LOCAL. - Split preparation of UDP sockets in logmessage() into socksetup().
Notes
Notes: svn path=/head/; revision=310434
Diffstat (limited to 'usr.bin/logger/logger.c')
-rw-r--r--usr.bin/logger/logger.c222
1 files changed, 163 insertions, 59 deletions
diff --git a/usr.bin/logger/logger.c b/usr.bin/logger/logger.c
index 49360f4a050f..b881636e0c0f 100644
--- a/usr.bin/logger/logger.c
+++ b/usr.bin/logger/logger.c
@@ -57,18 +57,22 @@ __FBSDID("$FreeBSD$");
#define SYSLOG_NAMES
#include <syslog.h>
+#define sstosa(ss) ((struct sockaddr *)(void *)ss)
+
+struct socks {
+ int sk_sock;
+ int sk_addrlen;
+ struct sockaddr_storage sk_addr;
+};
+
static int decode(char *, const CODE *);
static int pencode(char *);
-static void logmessage(int, const char *, const char *, const char *,
+static ssize_t socksetup(const char *, const char *, const char *,
+ struct socks **);
+static void logmessage(int, const char *, struct socks *, ssize_t,
const char *);
static void usage(void);
-struct socks {
- int sock;
- int addrlen;
- struct sockaddr_storage addr;
-};
-
#ifdef INET6
static int family = PF_UNSPEC; /* protocol family (IPv4, IPv6 or both) */
#else
@@ -85,17 +89,20 @@ static int send_to_all = 0; /* send message to all IPv4/IPv6 addresses */
int
main(int argc, char *argv[])
{
+ struct socks *socks;
+ ssize_t nsock;
int ch, logflags, pri;
char *tag, *host, buf[1024];
- const char *svcname;
+ const char *svcname, *src;
tag = NULL;
host = NULL;
svcname = "syslog";
+ src = NULL;
pri = LOG_USER | LOG_NOTICE;
logflags = 0;
unsetenv("TZ");
- while ((ch = getopt(argc, argv, "46Af:h:iP:p:st:")) != -1)
+ while ((ch = getopt(argc, argv, "46Af:h:iP:p:S:st:")) != -1)
switch((char)ch) {
case '4':
family = PF_INET;
@@ -128,6 +135,9 @@ main(int argc, char *argv[])
case 's': /* log to standard error */
logflags |= LOG_PERROR;
break;
+ case 'S': /* source address */
+ src = optarg;
+ break;
case 't': /* tag */
tag = optarg;
break;
@@ -138,6 +148,16 @@ main(int argc, char *argv[])
argc -= optind;
argv += optind;
+ if (host) {
+ nsock = socksetup(src, host, svcname, &socks);
+ if (nsock <= 0)
+ errx(1, "socket");
+ } else {
+ if (src)
+ errx(1, "-h option is missing.");
+ nsock = 0;
+ }
+
if (tag == NULL)
tag = getlogin();
/* setup for logging */
@@ -153,11 +173,11 @@ main(int argc, char *argv[])
for (p = buf, endp = buf + sizeof(buf) - 2; *argv;) {
len = strlen(*argv);
if (p + len > endp && p > buf) {
- logmessage(pri, tag, host, svcname, buf);
+ logmessage(pri, tag, socks, nsock, buf);
p = buf;
}
if (len > sizeof(buf) - 1)
- logmessage(pri, tag, host, svcname, *argv++);
+ logmessage(pri, tag, socks, nsock, *argv++);
else {
if (p != buf)
*p++ = ' ';
@@ -166,78 +186,162 @@ main(int argc, char *argv[])
}
}
if (p != buf)
- logmessage(pri, tag, host, svcname, buf);
+ logmessage(pri, tag, socks, nsock, buf);
} else
while (fgets(buf, sizeof(buf), stdin) != NULL)
- logmessage(pri, tag, host, svcname, buf);
+ logmessage(pri, tag, socks, nsock, buf);
exit(0);
}
+static ssize_t
+socksetup(const char *src, const char *dst, const char *svcname,
+ struct socks **socks)
+{
+ struct addrinfo hints, *res, *res0;
+ struct sockaddr_storage *ss_src[AF_MAX];
+ struct socks *sk;
+ ssize_t nsock = 0;
+ int error, maxs;
+
+ memset(&ss_src[0], 0, sizeof(ss_src));
+ if (src) {
+ char *p, *p0, *hs, *hbuf, *sbuf;
+
+ hbuf = sbuf = NULL;
+ p0 = p = strdup(src);
+ if (p0 == NULL)
+ err(1, "strdup failed");
+ hs = p0; /* point to search ":" */
+#ifdef INET6
+ /* -S option supports IPv6 addr in "[2001:db8::1]:service". */
+ if (*p0 == '[') {
+ p = strchr(p0, ']');
+ if (p == NULL)
+ errx(1, "\"]\" not found in src addr");
+ *p = '\0';
+ /* hs points just after ']' (':' or '\0'). */
+ hs = p + 1;
+ /*
+ * p points just after '[' while it points hs
+ * in the case of [].
+ */
+ p = ((p0 + 1) == (hs - 1)) ? hs : p0 + 1;
+ }
+#endif
+ if (*p != '\0') {
+ /* (p == hs) means ":514" or "[]:514". */
+ hbuf = (p == hs && *p == ':') ? NULL : p;
+ p = strchr(hs, ':');
+ if (p != NULL) {
+ *p = '\0';
+ sbuf = (*(p + 1) != '\0') ? p + 1 : NULL;
+ }
+ }
+ hints = (struct addrinfo){
+ .ai_family = family,
+ .ai_socktype = SOCK_DGRAM,
+ .ai_flags = AI_PASSIVE
+ };
+ error = getaddrinfo(hbuf, sbuf, &hints, &res0);
+ if (error)
+ errx(1, "%s: %s", gai_strerror(error), src);
+ for (res = res0; res; res = res->ai_next) {
+ switch (res->ai_family) {
+ case AF_INET:
+#ifdef INET6
+ case AF_INET6:
+#endif
+ if (ss_src[res->ai_family] != NULL)
+ continue;
+ ss_src[res->ai_family] =
+ malloc(sizeof(struct sockaddr_storage));
+ if (ss_src[res->ai_family] == NULL)
+ err(1, "malloc failed");
+ memcpy(ss_src[res->ai_family], res->ai_addr,
+ res->ai_addrlen);
+ }
+ }
+ freeaddrinfo(res0);
+ free(p0);
+ }
+
+ /* resolve hostname */
+ hints = (struct addrinfo){
+ .ai_family = family,
+ .ai_socktype = SOCK_DGRAM
+ };
+ error = getaddrinfo(dst, svcname, &hints, &res0);
+ if (error == EAI_SERVICE) {
+ warnx("%s/udp: unknown service", svcname);
+ error = getaddrinfo(dst, "514", &hints, &res);
+ }
+ if (error)
+ errx(1, "%s: %s", gai_strerror(error), dst);
+ /* count max number of sockets we may open */
+ maxs = 0;
+ for (res = res0; res; res = res->ai_next)
+ maxs++;
+ sk = calloc(maxs, sizeof(*sk));
+ if (sk == NULL)
+ errx(1, "couldn't allocate memory for sockets");
+ for (res = res0; res; res = res->ai_next) {
+ int s;
+
+ s = socket(res->ai_family, res->ai_socktype,
+ res->ai_protocol);
+ if (s < 0)
+ continue;
+ if (src && ss_src[res->ai_family] == NULL)
+ errx(1, "address family mismatch");
+
+ if (ss_src[res->ai_family]) {
+ error = bind(s, sstosa(ss_src[res->ai_family]),
+ ss_src[res->ai_family]->ss_len);
+ if (error < 0)
+ err(1, "bind");
+ }
+ sk[nsock] = (struct socks){
+ .sk_addrlen = res->ai_addrlen,
+ .sk_sock = s
+ };
+ memcpy(&sk[nsock].sk_addr, res->ai_addr, res->ai_addrlen);
+ nsock++;
+ }
+ freeaddrinfo(res0);
+
+ *socks = sk;
+ return (nsock);
+}
+
/*
* Send the message to syslog, either on the local host, or on a remote host
*/
static void
-logmessage(int pri, const char *tag, const char *host, const char *svcname,
- const char *buf)
+logmessage(int pri, const char *tag, struct socks *sk, ssize_t nsock,
+ const char *buf)
{
- static struct socks *socks;
- static int nsock = 0;
- struct addrinfo hints, *res, *r;
char *line;
- int maxs, len, sock, error, i, lsent;
+ int len, i, lsent;
- if (host == NULL) {
+ if (nsock == 0) {
syslog(pri, "%s", buf);
return;
}
-
- if (nsock <= 0) { /* set up socket stuff */
- /* resolve hostname */
- memset(&hints, 0, sizeof(hints));
- hints.ai_family = family;
- hints.ai_socktype = SOCK_DGRAM;
- error = getaddrinfo(host, svcname, &hints, &res);
- if (error == EAI_SERVICE) {
- warnx("%s/udp: unknown service", svcname);
- error = getaddrinfo(host, "514", &hints, &res);
- }
- if (error)
- errx(1, "%s: %s", gai_strerror(error), host);
- /* count max number of sockets we may open */
- for (maxs = 0, r = res; r; r = r->ai_next, maxs++);
- socks = malloc(maxs * sizeof(struct socks));
- if (!socks)
- errx(1, "couldn't allocate memory for sockets");
- for (r = res; r; r = r->ai_next) {
- sock = socket(r->ai_family, r->ai_socktype,
- r->ai_protocol);
- if (sock < 0)
- continue;
- memcpy(&socks[nsock].addr, r->ai_addr, r->ai_addrlen);
- socks[nsock].addrlen = r->ai_addrlen;
- socks[nsock++].sock = sock;
- }
- freeaddrinfo(res);
- if (nsock <= 0)
- errx(1, "socket");
- }
-
if ((len = asprintf(&line, "<%d>%s: %s", pri, tag, buf)) == -1)
errx(1, "asprintf");
lsent = -1;
- for (i = 0; i < nsock; ++i) {
- lsent = sendto(socks[i].sock, line, len, 0,
- (struct sockaddr *)&socks[i].addr,
- socks[i].addrlen);
+ for (i = 0; i < nsock; i++) {
+ lsent = sendto(sk[i].sk_sock, line, len, 0,
+ sstosa(&sk[i].sk_addr), sk[i].sk_addrlen);
if (lsent == len && !send_to_all)
break;
}
if (lsent != len) {
if (lsent == -1)
- warn ("sendto");
+ warn("sendto");
else
- warnx ("sendto: short send - %d bytes", lsent);
+ warnx("sendto: short send - %d bytes", lsent);
}
free(line);
@@ -290,7 +394,7 @@ usage(void)
{
(void)fprintf(stderr, "usage: %s\n",
"logger [-46Ais] [-f file] [-h host] [-P port] [-p pri] [-t tag]\n"
- " [message ...]"
+ " [-S addr:port] [message ...]"
);
exit(1);
}