Commit Diff


commit - 3c347461535dd1482d9f22df0ede0f245c092180
commit + a994c1755a6f17171db0bd9a56efd28f03954949
blob - 532bc19306dddc32e7c2236a2b958a02e9c0bf8b
blob + 020795e6496b2f22da447417c67793d1b001f5f6
--- gotd/gotd.c
+++ gotd/gotd.c
@@ -1983,6 +1983,8 @@ main(int argc, char **argv)
 	struct event evsigint, evsigterm, evsighup, evsigusr1, evsigchld;
 	int *pack_fds = NULL, *temp_fds = NULL;
 	struct gotd_repo *repo = NULL;
+	char *default_sender = NULL;
+	char hostname[HOST_NAME_MAX + 1];
 
 	TAILQ_INIT(&procs);
 
@@ -2109,6 +2111,11 @@ main(int argc, char **argv)
 	} else if (proc_id == PROC_NOTIFY) {
 		snprintf(title, sizeof(title), "%s %s",
 		    gotd_proc_names[proc_id], repo_path);
+		if (gethostname(hostname, sizeof(hostname)) == -1)
+			fatal("gethostname");
+		if (asprintf(&default_sender, "%s@%s",
+		    pw->pw_name, hostname) == -1)
+			fatal("asprintf");
 	} else
 		fatal("invalid process id %d", proc_id);
 
@@ -2217,7 +2224,7 @@ main(int argc, char **argv)
 		 */
 		unveil_notification_helpers();
 
-		notify_main(title);
+		notify_main(title, &gotd.repos, default_sender);
 		/* NOTREACHED */
 		exit(0);
 	default:
@@ -2252,6 +2259,7 @@ main(int argc, char **argv)
 	event_dispatch();
 
 	free(repo_path);
+	free(default_sender);
 	gotd_shutdown();
 
 	return 0;
blob - 536e8f08bcba8d30704aa3b6ee94d5a1bb340368
blob + dcc070cb7fdab140e8aa219b04f1423c773bd7b0
--- gotd/gotd.h
+++ gotd/gotd.h
@@ -497,6 +497,12 @@ struct gotd_imsg_auth {
 	gid_t egid;
 	int required_auth;
 	uint32_t client_id;
+};
+
+/* Structure for GOTD_IMSG_NOTIFY. */
+struct gotd_imsg_notify {
+	char repo_name[NAME_MAX];
+	char subject_line[64];
 };
 
 int parse_config(const char *, enum gotd_procid, struct gotd *);
blob - 78359bad4c5f1afe2fbc0dbf0c5a37663f8056b8
blob + bbb8bc71084a768db3ea5cabaf3053203b4ccfcc
--- gotd/notify.c
+++ gotd/notify.c
@@ -18,6 +18,7 @@
 #include <sys/queue.h>
 #include <sys/tree.h>
 #include <sys/socket.h>
+#include <sys/wait.h>
 
 #include <errno.h>
 #include <event.h>
@@ -27,6 +28,7 @@
 #include <signal.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <string.h>
 #include <imsg.h>
 #include <unistd.h>
 
@@ -41,6 +43,8 @@ static struct gotd_notify {
 	pid_t pid;
 	const char *title;
 	struct gotd_imsgev parent_iev;
+	struct gotd_repolist *repos;
+	const char *default_sender;
 } gotd_notify;
 
 void gotd_notify_sighdlr(int sig, short event, void *arg);
@@ -72,6 +76,135 @@ gotd_notify_sighdlr(int sig, short event, void *arg)
 }
 
 static void
+run_notification_helper(const char *prog, const char **argv, int fd)
+{
+	const struct got_error *err = NULL;
+	pid_t pid;
+	int child_status;
+
+	pid = fork();
+	if (pid == -1) {
+		err = got_error_from_errno("fork");
+		log_warn("%s", err->msg);
+		return;
+	} else if (pid == 0) {
+		signal(SIGQUIT, SIG_DFL);
+		signal(SIGINT, SIG_DFL);
+		signal(SIGCHLD, SIG_DFL);
+
+		if (dup2(fd, STDIN_FILENO) == -1) {
+			fprintf(stderr, "%s: dup2: %s\n", getprogname(),
+			    strerror(errno));
+			_exit(1);
+		}
+
+		closefrom(STDERR_FILENO + 1);
+
+		if (execv(prog, (char *const *)argv) == -1) {
+			fprintf(stderr, "%s: exec %s: %s\n", getprogname(),
+			    prog, strerror(errno));
+			_exit(1);
+		}
+
+		/* not reached */
+	}
+
+	if (waitpid(pid, &child_status, 0) == -1) {
+		err = got_error_from_errno("waitpid");
+		goto done;
+	}
+
+	if (!WIFEXITED(child_status)) {
+		err = got_error(GOT_ERR_PRIVSEP_DIED);
+		goto done;
+	}
+
+	if (WEXITSTATUS(child_status) != 0)
+		err = got_error(GOT_ERR_PRIVSEP_EXIT);
+done:
+	if (err)
+		log_warnx("%s: child %s pid %d: %s", gotd_notify.title,
+		    prog, pid, err->msg);
+}
+
+static void
+notify_email(struct gotd_notification_target *target, const char *subject_line,
+    int fd)
+{
+	const char *argv[9];
+	int i = 0;
+
+	argv[i++] = GOTD_PATH_PROG_NOTIFY_EMAIL;
+
+	argv[i++] = "-f";
+	if (target->conf.email.sender)
+		argv[i++] = target->conf.email.sender;
+	else
+		argv[i++] = gotd_notify.default_sender;
+
+	if (target->conf.email.responder) {
+		argv[i++] = "-r";
+		argv[i++] = target->conf.email.responder;
+	}
+	
+	argv[i++] = "-s";
+	argv[i++] = subject_line;
+
+	argv[i++] = target->conf.email.recipient;
+
+	argv[i] = NULL;
+
+	run_notification_helper(GOTD_PATH_PROG_NOTIFY_EMAIL, argv, fd);
+}
+
+static void
+notify_http(struct gotd_notification_target *target, const char *subject_line,
+    int fd)
+{
+	const char *argv[10] = { 0 }; /* TODO */
+
+	run_notification_helper(GOTD_PATH_PROG_NOTIFY_HTTP, argv, fd);
+}
+
+static const struct got_error *
+send_notifications(struct imsg *imsg)
+{
+	struct gotd_imsg_notify inotify;
+	size_t datalen;
+	struct gotd_repo *repo;
+	struct gotd_notification_target *target;
+
+	datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
+	if (datalen != sizeof(inotify))
+		return got_error(GOT_ERR_PRIVSEP_LEN);
+
+	memcpy(&inotify, imsg->data, datalen);
+
+	if (imsg->fd == -1)
+		return got_error(GOT_ERR_PRIVSEP_NO_FD);
+
+	TAILQ_FOREACH(repo, gotd_notify.repos, entry) {
+		if (strcmp(repo->name, inotify.repo_name) == 0)
+			break;
+	}
+	if (repo == NULL)
+		return got_error(GOT_ERR_PRIVSEP_MSG);
+
+	STAILQ_FOREACH(target, &repo->notification_targets, entry) {
+		switch (target->type) {
+		case GOTD_NOTIFICATION_VIA_EMAIL:
+			notify_email(target, inotify.subject_line, imsg->fd);
+			break;
+		case GOTD_NOTIFICATION_VIA_HTTP:
+			notify_http(target, inotify.subject_line, imsg->fd);
+			break;
+		}
+	}
+
+	return NULL;
+}
+
+static void
 notify_dispatch(int fd, short event, void *arg)
 {
 	struct gotd_imsgev *iev = arg;
@@ -110,6 +243,10 @@ notify_dispatch(int fd, short event, void *arg)
 			break;
 
 		switch (imsg.hdr.type) {
+		case GOTD_IMSG_NOTIFY:
+			err = send_notifications(&imsg);
+			if (err)
+				break;
 		default:
 			log_debug("unexpected imsg %d", imsg.hdr.type);
 			break;
@@ -131,12 +268,15 @@ done:
 }
 
 void
-notify_main(const char *title)
+notify_main(const char *title, struct gotd_repolist *repos,
+    const char *default_sender)
 {
 	const struct got_error *err = NULL;
 	struct event evsigint, evsigterm, evsighup, evsigusr1;
 
 	gotd_notify.title = title;
+	gotd_notify.repos = repos;
+	gotd_notify.default_sender = default_sender;
 	gotd_notify.pid = getpid();
 
 	signal_set(&evsigint, SIGINT, gotd_notify_sighdlr, NULL);
blob - 5ba452e52c2a67baf8c8220364b01201f02427a0
blob + 8772e7f321719d0df0848da2b7d3155f44379173
--- gotd/notify.h
+++ gotd/notify.h
@@ -14,4 +14,4 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-void notify_main(const char *);
+void notify_main(const char *, struct gotd_repolist *, const char *);