1/*-
2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3 *
4 * Copyright (c) 2010 Pawel Jakub Dawidek <pjd@FreeBSD.org>
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29#include <sys/cdefs.h>
30__FBSDID("$FreeBSD: stable/11/sbin/hastd/event.c 330449 2018-03-05 07:26:05Z eadler $");
31
32#include <errno.h>
33
34#include "hast.h"
35#include "hast_proto.h"
36#include "hooks.h"
37#include "nv.h"
38#include "pjdlog.h"
39#include "proto.h"
40#include "subr.h"
41
42#include "event.h"
43
44void
45event_send(const struct hast_resource *res, int event)
46{
47	struct nv *nvin, *nvout;
48	int error;
49
50	PJDLOG_ASSERT(res != NULL);
51	PJDLOG_ASSERT(event >= EVENT_MIN && event <= EVENT_MAX);
52
53	nvin = nvout = NULL;
54
55	/*
56	 * Prepare and send event to parent process.
57	 */
58	nvout = nv_alloc();
59	nv_add_uint8(nvout, (uint8_t)event, "event");
60	error = nv_error(nvout);
61	if (error != 0) {
62		pjdlog_common(LOG_ERR, 0, error,
63		    "Unable to prepare event header");
64		goto done;
65	}
66	if (hast_proto_send(res, res->hr_event, nvout, NULL, 0) == -1) {
67		pjdlog_errno(LOG_ERR, "Unable to send event header");
68		goto done;
69	}
70	if (hast_proto_recv_hdr(res->hr_event, &nvin) == -1) {
71		pjdlog_errno(LOG_ERR, "Unable to receive event header");
72		goto done;
73	}
74	/*
75	 * Do nothing with the answer. We only wait for it to be sure not
76	 * to exit too quickly after sending an event and exiting immediately.
77	 */
78done:
79	if (nvin != NULL)
80		nv_free(nvin);
81	if (nvout != NULL)
82		nv_free(nvout);
83}
84
85int
86event_recv(const struct hast_resource *res)
87{
88	struct nv *nvin, *nvout;
89	const char *evstr;
90	uint8_t event;
91	int error;
92
93	PJDLOG_ASSERT(res != NULL);
94
95	nvin = nvout = NULL;
96
97	if (hast_proto_recv_hdr(res->hr_event, &nvin) == -1) {
98		/*
99		 * First error log as debug. This is because worker process
100		 * most likely exited.
101		 */
102		pjdlog_common(LOG_DEBUG, 1, errno,
103		    "Unable to receive event header");
104		goto fail;
105	}
106
107	event = nv_get_uint8(nvin, "event");
108	if (event == EVENT_NONE) {
109		pjdlog_error("Event header is missing 'event' field.");
110		goto fail;
111	}
112
113	switch (event) {
114	case EVENT_CONNECT:
115		evstr = "connect";
116		break;
117	case EVENT_DISCONNECT:
118		evstr = "disconnect";
119		break;
120	case EVENT_SYNCSTART:
121		evstr = "syncstart";
122		break;
123	case EVENT_SYNCDONE:
124		evstr = "syncdone";
125		break;
126	case EVENT_SYNCINTR:
127		evstr = "syncintr";
128		break;
129	case EVENT_SPLITBRAIN:
130		evstr = "split-brain";
131		break;
132	default:
133		pjdlog_error("Event header contain invalid event number (%hhu).",
134		    event);
135		goto fail;
136	}
137
138	pjdlog_prefix_set("[%s] (%s) ", res->hr_name, role2str(res->hr_role));
139	hook_exec(res->hr_exec, evstr, res->hr_name, NULL);
140	pjdlog_prefix_set("%s", "");
141
142	nvout = nv_alloc();
143	nv_add_int16(nvout, 0, "error");
144	error = nv_error(nvout);
145	if (error != 0) {
146		pjdlog_common(LOG_ERR, 0, error,
147		    "Unable to prepare event header");
148		goto fail;
149	}
150	if (hast_proto_send(res, res->hr_event, nvout, NULL, 0) == -1) {
151		pjdlog_errno(LOG_ERR, "Unable to send event header");
152		goto fail;
153	}
154	nv_free(nvin);
155	nv_free(nvout);
156	return (0);
157fail:
158	if (nvin != NULL)
159		nv_free(nvin);
160	if (nvout != NULL)
161		nv_free(nvout);
162	return (-1);
163}
164