Commit Diff


commit - 8285e71aecfd159643f1705f24709fc30a8cbda0
commit + 8c39831b06ec0976139042564390b6064cb9cb5e
blob - 2e293cfda482ac271343e8604d92b018614777f7
blob + 28e61b6461c301e8d425680ae7af678007fc4ce8
--- gotd/repo_write.c
+++ gotd/repo_write.c
@@ -1788,11 +1788,16 @@ render_notification(struct imsg *imsg, struct gotd_ims
 {
 	const struct got_error *err = NULL;
 	struct gotd_imsg_notification_content ireq;
-	size_t datalen;
+	size_t datalen, len;
 	char *refname;
+	struct ibuf *wbuf;
+	int fd;
 
-	if (imsg->fd == -1)
+	fd = imsg_get_fd(imsg);
+	if (fd == -1) {
+		log_debug("%s: no fd!", __func__);
 		return got_error(GOT_ERR_PRIVSEP_NO_FD);
+	}
 
 	datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
 	if (datalen < sizeof(ireq))
@@ -1809,20 +1814,44 @@ render_notification(struct imsg *imsg, struct gotd_ims
 
 	switch (ireq.action) {
 	case GOTD_NOTIF_ACTION_CREATED:
-		err = notify_created_ref(refname, ireq.new_id, iev, imsg->fd);
+		err = notify_created_ref(refname, ireq.new_id, iev, fd);
 		break;
 	case GOTD_NOTIF_ACTION_REMOVED:
-		err = notify_removed_ref(refname, ireq.old_id, iev, imsg->fd);
+		err = notify_removed_ref(refname, ireq.old_id, iev, fd);
 		break;
 	case GOTD_NOTIF_ACTION_CHANGED:
 		err = notify_changed_ref(refname, ireq.old_id, ireq.new_id,
-		    iev, imsg->fd);
+		    iev, fd);
 		break;
 	}
 
-	/* TODO send GOTD_IMSG_NOTIFY */
+	if (fsync(fd) == -1) {
+		err = got_error_from_errno("fsync");
+		goto done;
+	}
 
+	len = sizeof(ireq) + ireq.refname_len;
+	wbuf = imsg_create(&iev->ibuf, GOTD_IMSG_NOTIFY, PROC_REPO_WRITE,
+	    repo_write.pid, len);
+	if (wbuf == NULL) {
+		err = got_error_from_errno("imsg_create REF");
+		goto done;
+	}
+	if (imsg_add(wbuf, &ireq, sizeof(ireq)) == -1) {
+		err = got_error_from_errno("imsg_add NOTIFY");
+		goto done;
+	}
+	if (imsg_add(wbuf, refname, ireq.refname_len) == -1) {
+		err = got_error_from_errno("imsg_add NOTIFY");
+		goto done;
+	}
+
+	imsg_close(&iev->ibuf, wbuf);
+	gotd_imsg_event_add(iev);
+done:
 	free(refname);
+	if (close(fd) == -1 && err == NULL)
+		err = got_error_from_errno("close");
 	return err;
 }
 
blob - 133e70534548d1d8d4987921c6de3a96618c9da2
blob + 44fc1ca64be81248433595c7649791a84625645a
--- gotd/session.c
+++ gotd/session.c
@@ -496,18 +496,16 @@ static const struct got_error *
 forward_notification(struct gotd_session_client *client, struct imsg *imsg)
 {
 	const struct got_error *err = NULL;
-	struct gotd_imsgev *iev = &client->repo_child_iev;
+	struct gotd_imsgev *iev = &gotd_session.notifier_iev;
 	struct gotd_session_notif *notif, *tmp;
 	struct gotd_imsg_notification_content icontent;
 	char *refname = NULL;
 	size_t datalen;
 	struct gotd_imsg_notify inotify;
 	char hostname[HOST_NAME_MAX + 1];
+	int fd = -1;
 
 	memset(&inotify, 0, sizeof(inotify));
-
-	if (imsg->fd == -1)
-		return got_error(GOT_ERR_PRIVSEP_NO_FD);
 
 	datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
 	if (datalen < sizeof(icontent))
@@ -520,7 +518,7 @@ forward_notification(struct gotd_session_client *clien
 		return got_error_from_errno("strndup");
 
 	STAILQ_FOREACH_SAFE(notif, &notifications, entry, tmp) {
-		if (notif->action != icontent.action ||
+		if (notif->action != icontent.action || notif->fd == -1 ||
 		    strcmp(notif->refname, refname) != 0)
 			continue;
 		if (notif->action == GOTD_NOTIF_ACTION_CREATED) {
@@ -573,8 +571,13 @@ forward_notification(struct gotd_session_client *clien
 		    "%s: %s: UID %d %s %s", hostname, gotd_session.repo_cfg->name,
 		    client->euid, action, notif->refname);
 
+		fd = dup(notif->fd);
+		if (fd == -1) {
+			err = got_error_from_errno("dup");
+			goto done;
+		}
 		if (gotd_imsg_compose_event(iev, GOTD_IMSG_NOTIFY,
-		    PROC_SESSION_WRITE, imsg->fd, &inotify, sizeof(inotify))
+		    PROC_SESSION_WRITE, fd, &inotify, sizeof(inotify))
 		    == -1) {
 			err = got_error_from_errno("imsg compose NOTIFY");
 			goto done;
@@ -841,7 +844,7 @@ recv_notification_content(uint32_t *client_id, struct 
 	log_debug("notification content received");
 
 	datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
-	if (datalen != sizeof(inotif))
+	if (datalen < sizeof(inotif))
 		return got_error(GOT_ERR_PRIVSEP_LEN);
 	memcpy(&inotif, imsg->data, sizeof(inotif));
 
@@ -920,6 +923,7 @@ session_dispatch_repo_child(int fd, short event, void 
 			err = recv_notification_content(&client_id, &imsg);
 			if (err == NULL)
 				do_notify = 1;
+			break;
 		default:
 			log_debug("unexpected imsg %d", imsg.hdr.type);
 			break;
@@ -1673,6 +1677,7 @@ recv_notifier(struct imsg *imsg)
 	struct gotd_imsgev *iev = &gotd_session.notifier_iev;
 	struct gotd_session_client *client = &gotd_session_client;
 	size_t datalen;
+	int fd;
 
 	if (client->state != GOTD_STATE_EXPECT_LIST_REFS)
 		return got_error(GOT_ERR_PRIVSEP_MSG);
@@ -1685,10 +1690,11 @@ recv_notifier(struct imsg *imsg)
 	if (datalen != 0)
 		return got_error(GOT_ERR_PRIVSEP_LEN);
 
-	if (imsg->fd == -1)
+	fd = imsg_get_fd(imsg);
+	if (fd == -1)
 		return NULL; /* notifications unused */
 
-	imsg_init(&iev->ibuf, imsg->fd);
+	imsg_init(&iev->ibuf, fd);
 	iev->handler = session_dispatch_notifier;
 	iev->events = EV_READ;
 	iev->handler_arg = NULL;