1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at http://smartos.org/CDDL
10  *
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file.
16  *
17  * If applicable, add the following below this CDDL HEADER, with the
18  * fields enclosed by brackets "[]" replaced with your own identifying
19  * information: Portions Copyright [yyyy] [name of copyright owner]
20  *
21  * CDDL HEADER END
22  *
23  * Copyright 2020 Joyent, Inc.
24  *
25  */
26 
27 #include <err.h>
28 #include <errno.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <unistd.h>
33 #include <sys/debug.h>
34 #include <sys/sysmacros.h>
35 #include <sys/types.h>
36 #include <libsysevent.h>
37 #include <sys/sysevent/eventdefs.h>
38 
39 FILE *out;
40 
41 static void
42 process_event(sysevent_t *ev)
43 {
44 	char *class = NULL;
45 	char *subclass = NULL;
46 
47 	/* get sysevent metadata and add to the nvlist */
48 	class = sysevent_get_class_name(ev);
49 	subclass = sysevent_get_subclass_name(ev);
50 
51 	if (class == NULL || subclass == NULL)
52 		errx(EXIT_FAILURE, "failed to retrieve sysevent metadata");
53 
54 	VERIFY0(strcmp(class, EC_ZFS));
55 	VERIFY0(strcmp(subclass, ESC_ZFS_RESILVER_START));
56 
57 	flockfile(out);
58 	(void) fprintf(out, "Received %s.%s event\n", class, subclass);
59 	(void) fflush(out);
60 	funlockfile(out);
61 }
62 
63 static void
64 child_fatal(int fd, const char *msg, ...)
65 {
66 	va_list ap;
67 	int fail = EXIT_FAILURE;
68 
69 	va_start(ap, msg);
70 	(void) vfprintf(stderr, msg, ap);
71 	va_end(ap);
72 	(void) fputc('\n', stderr);
73 
74 	(void) write(fd, &fail, sizeof (fail));
75 	(void) close(fd);
76 	exit(EXIT_FAILURE);
77 }
78 
79 static void
80 do_child(int fd)
81 {
82 	const char *subclasses[] = {
83 		ESC_ZFS_RESILVER_START,
84 	};
85 	sysevent_handle_t *handle;
86 	int ret = 0;
87 
88 	if ((handle = sysevent_bind_handle(process_event)) == NULL) {
89 		child_fatal(fd, "sysevent_bind_handle() failed: %s",
90 		    strerror(errno));
91 	}
92 
93 	if (sysevent_subscribe_event(handle, EC_ZFS, subclasses,
94 	    ARRAY_SIZE(subclasses)) != 0) {
95 		child_fatal(fd, "failed to subscribe to sysevents: %s",
96 		    strerror(errno));
97 	}
98 
99 	(void) write(fd, &ret, sizeof (ret));
100 	(void) close(fd);
101 
102 	/* leave stderr open so any errors get captured by test harness */
103 	(void) fclose(stdin);
104 	(void) fclose(stdout);
105 
106 	for (;;)
107 		(void) pause();
108 }
109 
110 int
111 main(int argc, char **argv)
112 {
113 	pid_t child;
114 	int fds[2];
115 	int ret = 0;
116 
117 	if (argc < 2) {
118 		(void) fprintf(stderr, "Usage: %s outfile\n", argv[0]);
119 		exit(EXIT_FAILURE);
120 	}
121 
122 	if ((out = fopen(argv[1], "w")) == NULL)
123 		err(EXIT_FAILURE, "unable to open %s", argv[1]);
124 
125 	VERIFY0(pipe(fds));
126 
127 	switch (child = fork()) {
128 	case -1:
129 		err(EXIT_FAILURE, "unable to fork");
130 	case 0:
131 		do_child(fds[1]);
132 		break;
133 	default:
134 		break;
135 	}
136 
137 	(void) close(fds[1]);
138 
139 	if (read(fds[0], &ret, sizeof (ret)) < 0)
140 		err(EXIT_FAILURE, "failure waiting on child");
141 
142 	if (ret != 0)
143 		return (ret);
144 
145 	(void) close(fds[0]);
146 	(void) printf("%d\n", child);
147 	return (0);
148 }
149