"GOT", but the "O" is a cute, smiling pufferfish. Index | Thread | Search

From:
Omar Polo <op@omarpolo.com>
Subject:
got-notify-email: spilt dial() out of send_email()
To:
gameoftrees@openbsd.org
Date:
Wed, 20 Mar 2024 11:43:37 +0100

Download raw body.

Thread
By splitting out a dial() function from send_mail(), we can further
reduce the pledge() in main down to "stdio".  Other than being nice on
its own, this also helps -portable, for e.g. on freebsd we could use
capsicum(4).

While here, do the usual loop around getaddrinfo() in case we fail to
connect to the first result.

ok?

diff /home/op/w/got
commit - dfa6ae4cb7d2e0474c8458b5622eca0385470c01
path + /home/op/w/got
blob - d2e507fdfece9c9538bfe12b6cd820f899d7a552
file + gotd/libexec/got-notify-email/got-notify-email.c
--- gotd/libexec/got-notify-email/got-notify-email.c
+++ gotd/libexec/got-notify-email/got-notify-email.c
@@ -17,6 +17,7 @@
 #include <sys/types.h>
 #include <sys/socket.h>
 
+#include <errno.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -42,6 +43,48 @@ usage(void)
 	exit(1);
 }
 
+static int
+dial(const char *host, const char *port)
+{
+	struct addrinfo	 hints, *res, *res0;
+	const char	*cause = NULL;
+	int		 s, error, save_errno;
+
+	memset(&hints, 0, sizeof(hints));
+	hints.ai_family = AF_UNSPEC;
+	hints.ai_socktype = SOCK_STREAM;
+	error = getaddrinfo(host, port, &hints, &res0);
+	if (error)
+		errx(1, "failed to resolve %s:%s: %s", host, port,
+		    gai_strerror(error));
+
+	s = -1;
+	for (res = res0; res; res = res->ai_next) {
+		s = socket(res->ai_family, res->ai_socktype,
+		    res->ai_protocol);
+		if (s == -1) {
+			cause = "socket";
+			continue;
+		}
+
+		if (connect(s, res->ai_addr, res->ai_addrlen) == -1) {
+			cause = "connect";
+			save_errno = errno;
+			close(s);
+			errno = save_errno;
+			s = -1;
+			continue;
+		}
+
+		break;
+	}
+
+	freeaddrinfo(res0);
+	if (s == -1)
+		err(1, "%s", cause);
+	return s;
+}
+
 static char *
 set_default_fromaddr(void)
 {
@@ -156,16 +199,14 @@ get_datestr(time_t *time, char *datebuf)
 }
 
 static void
-send_email(const char *myfromaddr, const char *fromaddr,
+send_email(int s, const char *myfromaddr, const char *fromaddr,
     const char *recipient, const char *replytoaddr,
-    const char *subject, const char *hostname, const char *port)
+    const char *subject)
 {
 	const struct got_error *error;
 	char *line = NULL;
 	size_t linesize = 0;
 	ssize_t linelen;
-	struct addrinfo hints, *res = NULL;
-	int s = -1, ret;
 	time_t now;
 	char datebuf[26];
 	char *datestr;
@@ -173,21 +214,6 @@ send_email(const char *myfromaddr, const char *fromadd
 	now = time(NULL);
 	datestr = get_datestr(&now, datebuf);
 
-	memset(&hints, 0, sizeof(hints));
-	hints.ai_family = AF_INET;
-	hints.ai_socktype = SOCK_STREAM;
-
-	ret = getaddrinfo(hostname, port, &hints, &res);
-	if (ret)
-		errx(1, "getaddrinfo: %s", gai_strerror(ret));
-
-	s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
-	if (s == -1)
-		err(1, "socket");
-
-	if (connect(s, res->ai_addr, res->ai_addrlen) == -1)
-		err(1, "connect %s:%s", hostname, port);
-
 	if (read_smtp_code(s, "220"))
 		errx(1, "unexpected SMTP greeting received");
 	if (skip_to_crlf(s))
@@ -266,8 +292,6 @@ send_email(const char *myfromaddr, const char *fromadd
 
 	close(s);
 	free(line);
-	if (res)
-		freeaddrinfo(res);
 }
 
 int
@@ -280,7 +304,7 @@ main(int argc, char *argv[])
 	const char *port = "25";
 	const char *errstr;
 	char *timeoutstr;
-	int ch;
+	int ch, s;
 
 	while ((ch = getopt(argc, argv, "f:r:s:h:p:")) != -1) {
 		switch (ch) {
@@ -336,9 +360,16 @@ main(int argc, char *argv[])
 	if (fromaddr == NULL)
 		fromaddr = default_fromaddr;
 
-	send_email(default_fromaddr, fromaddr, recipient, replytoaddr,
-	    subject, hostname, port);
+	s = dial(hostname, port);
 
+#ifndef PROFILE
+	if (pledge("stdio", NULL) == -1)
+		err(1, "pledge");
+#endif
+
+	send_email(s, default_fromaddr, fromaddr, recipient, replytoaddr,
+	    subject);
+
 	free(default_fromaddr);
 	return 0;
 }