commit - 3c347461535dd1482d9f22df0ede0f245c092180
commit + a994c1755a6f17171db0bd9a56efd28f03954949
blob - 532bc19306dddc32e7c2236a2b958a02e9c0bf8b
blob + 020795e6496b2f22da447417c67793d1b001f5f6
--- gotd/gotd.c
+++ gotd/gotd.c
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);
} 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);
*/
unveil_notification_helpers();
- notify_main(title);
+ notify_main(title, &gotd.repos, default_sender);
/* NOTREACHED */
exit(0);
default:
event_dispatch();
free(repo_path);
+ free(default_sender);
gotd_shutdown();
return 0;
blob - 536e8f08bcba8d30704aa3b6ee94d5a1bb340368
blob + dcc070cb7fdab140e8aa219b04f1423c773bd7b0
--- gotd/gotd.h
+++ gotd/gotd.h
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
#include <sys/queue.h>
#include <sys/tree.h>
#include <sys/socket.h>
+#include <sys/wait.h>
#include <errno.h>
#include <event.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
#include <imsg.h>
#include <unistd.h>
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);
}
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;
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;
}
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
* 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 *);