10c06d385Sjwpoduska /*
20c06d385Sjwpoduska  * CDDL HEADER START
30c06d385Sjwpoduska  *
40c06d385Sjwpoduska  * The contents of this file are subject to the terms of the
50c06d385Sjwpoduska  * Common Development and Distribution License, Version 1.0 only
60c06d385Sjwpoduska  * (the "License").  You may not use this file except in compliance
70c06d385Sjwpoduska  * with the License.
80c06d385Sjwpoduska  *
90c06d385Sjwpoduska  * You can obtain a copy of the license at http://smartos.org/CDDL
100c06d385Sjwpoduska  *
110c06d385Sjwpoduska  * See the License for the specific language governing permissions
120c06d385Sjwpoduska  * and limitations under the License.
130c06d385Sjwpoduska  *
140c06d385Sjwpoduska  * When distributing Covered Code, include this CDDL HEADER in each
150c06d385Sjwpoduska  * file.
160c06d385Sjwpoduska  *
170c06d385Sjwpoduska  * If applicable, add the following below this CDDL HEADER, with the
180c06d385Sjwpoduska  * fields enclosed by brackets "[]" replaced with your own identifying
190c06d385Sjwpoduska  * information: Portions Copyright [yyyy] [name of copyright owner]
200c06d385Sjwpoduska  *
210c06d385Sjwpoduska  * CDDL HEADER END
220c06d385Sjwpoduska  *
230c06d385Sjwpoduska  * Copyright 2020 Joyent, Inc.
240c06d385Sjwpoduska  *
250c06d385Sjwpoduska  */
260c06d385Sjwpoduska 
270c06d385Sjwpoduska #include <err.h>
280c06d385Sjwpoduska #include <errno.h>
290c06d385Sjwpoduska #include <stdio.h>
300c06d385Sjwpoduska #include <stdlib.h>
310c06d385Sjwpoduska #include <string.h>
320c06d385Sjwpoduska #include <unistd.h>
330c06d385Sjwpoduska #include <sys/debug.h>
340c06d385Sjwpoduska #include <sys/sysmacros.h>
350c06d385Sjwpoduska #include <sys/types.h>
360c06d385Sjwpoduska #include <libsysevent.h>
370c06d385Sjwpoduska #include <sys/sysevent/eventdefs.h>
380c06d385Sjwpoduska 
390c06d385Sjwpoduska FILE *out;
400c06d385Sjwpoduska 
410c06d385Sjwpoduska static void
process_event(sysevent_t * ev)420c06d385Sjwpoduska process_event(sysevent_t *ev)
430c06d385Sjwpoduska {
440c06d385Sjwpoduska 	char *class = NULL;
450c06d385Sjwpoduska 	char *subclass = NULL;
460c06d385Sjwpoduska 
470c06d385Sjwpoduska 	/* get sysevent metadata and add to the nvlist */
480c06d385Sjwpoduska 	class = sysevent_get_class_name(ev);
490c06d385Sjwpoduska 	subclass = sysevent_get_subclass_name(ev);
500c06d385Sjwpoduska 
510c06d385Sjwpoduska 	if (class == NULL || subclass == NULL)
520c06d385Sjwpoduska 		errx(EXIT_FAILURE, "failed to retrieve sysevent metadata");
530c06d385Sjwpoduska 
540c06d385Sjwpoduska 	VERIFY0(strcmp(class, EC_ZFS));
550c06d385Sjwpoduska 
560c06d385Sjwpoduska 	flockfile(out);
570c06d385Sjwpoduska 	(void) fprintf(out, "Received %s.%s event\n", class, subclass);
580c06d385Sjwpoduska 	(void) fflush(out);
590c06d385Sjwpoduska 	funlockfile(out);
600c06d385Sjwpoduska }
610c06d385Sjwpoduska 
620c06d385Sjwpoduska static void
child_fatal(int fd,const char * msg,...)630c06d385Sjwpoduska child_fatal(int fd, const char *msg, ...)
640c06d385Sjwpoduska {
650c06d385Sjwpoduska 	va_list ap;
660c06d385Sjwpoduska 	int fail = EXIT_FAILURE;
670c06d385Sjwpoduska 
680c06d385Sjwpoduska 	va_start(ap, msg);
690c06d385Sjwpoduska 	(void) vfprintf(stderr, msg, ap);
700c06d385Sjwpoduska 	va_end(ap);
710c06d385Sjwpoduska 	(void) fputc('\n', stderr);
720c06d385Sjwpoduska 
730c06d385Sjwpoduska 	(void) write(fd, &fail, sizeof (fail));
740c06d385Sjwpoduska 	(void) close(fd);
750c06d385Sjwpoduska 	exit(EXIT_FAILURE);
760c06d385Sjwpoduska }
770c06d385Sjwpoduska 
780c06d385Sjwpoduska static void
do_child(int fd,char * const subclasses[],size_t n)79*165c5c6fSJohn Poduska do_child(int fd, char * const subclasses[], size_t n)
800c06d385Sjwpoduska {
810c06d385Sjwpoduska 	sysevent_handle_t *handle;
820c06d385Sjwpoduska 	int ret = 0;
830c06d385Sjwpoduska 
840c06d385Sjwpoduska 	if ((handle = sysevent_bind_handle(process_event)) == NULL) {
850c06d385Sjwpoduska 		child_fatal(fd, "sysevent_bind_handle() failed: %s",
860c06d385Sjwpoduska 		    strerror(errno));
870c06d385Sjwpoduska 	}
880c06d385Sjwpoduska 
89*165c5c6fSJohn Poduska 	if (sysevent_subscribe_event(handle, EC_ZFS,
90*165c5c6fSJohn Poduska 	    (const char **)subclasses, n) != 0) {
910c06d385Sjwpoduska 		child_fatal(fd, "failed to subscribe to sysevents: %s",
920c06d385Sjwpoduska 		    strerror(errno));
930c06d385Sjwpoduska 	}
940c06d385Sjwpoduska 
950c06d385Sjwpoduska 	(void) write(fd, &ret, sizeof (ret));
960c06d385Sjwpoduska 	(void) close(fd);
970c06d385Sjwpoduska 
980c06d385Sjwpoduska 	/* leave stderr open so any errors get captured by test harness */
990c06d385Sjwpoduska 	(void) fclose(stdin);
1000c06d385Sjwpoduska 	(void) fclose(stdout);
1010c06d385Sjwpoduska 
1020c06d385Sjwpoduska 	for (;;)
1030c06d385Sjwpoduska 		(void) pause();
1040c06d385Sjwpoduska }
1050c06d385Sjwpoduska 
106*165c5c6fSJohn Poduska static void
usage(const char * name)107*165c5c6fSJohn Poduska usage(const char *name)
108*165c5c6fSJohn Poduska {
109*165c5c6fSJohn Poduska 	(void) fprintf(stderr, "Usage: %s [-o outfile] zfs_event...\n", name);
110*165c5c6fSJohn Poduska 	exit(2);
111*165c5c6fSJohn Poduska }
112*165c5c6fSJohn Poduska 
1130c06d385Sjwpoduska int
main(int argc,char * const argv[])114*165c5c6fSJohn Poduska main(int argc, char * const argv[])
1150c06d385Sjwpoduska {
116*165c5c6fSJohn Poduska 	const char *outfile = NULL;
1170c06d385Sjwpoduska 	pid_t child;
1180c06d385Sjwpoduska 	int fds[2];
1190c06d385Sjwpoduska 	int ret = 0;
120*165c5c6fSJohn Poduska 	int c;
121*165c5c6fSJohn Poduska 
122*165c5c6fSJohn Poduska 	while ((c = getopt(argc, argv, "o:")) != -1) {
123*165c5c6fSJohn Poduska 		switch (c) {
124*165c5c6fSJohn Poduska 		case 'o':
125*165c5c6fSJohn Poduska 			outfile = optarg;
126*165c5c6fSJohn Poduska 			break;
127*165c5c6fSJohn Poduska 		case '?':
128*165c5c6fSJohn Poduska 			(void) fprintf(stderr, "Invalid option -%c\n", optopt);
129*165c5c6fSJohn Poduska 			usage(argv[0]);
130*165c5c6fSJohn Poduska 		}
1310c06d385Sjwpoduska 	}
1320c06d385Sjwpoduska 
133*165c5c6fSJohn Poduska 	if (outfile != NULL) {
134*165c5c6fSJohn Poduska 		if ((out = fopen(optarg, "w")) == NULL)
135*165c5c6fSJohn Poduska 			err(EXIT_FAILURE, "unable to open %s", optarg);
136*165c5c6fSJohn Poduska 	} else {
137*165c5c6fSJohn Poduska 		out = stdout;
138*165c5c6fSJohn Poduska 	}
1390c06d385Sjwpoduska 
1400c06d385Sjwpoduska 	VERIFY0(pipe(fds));
1410c06d385Sjwpoduska 
1420c06d385Sjwpoduska 	switch (child = fork()) {
1430c06d385Sjwpoduska 	case -1:
1440c06d385Sjwpoduska 		err(EXIT_FAILURE, "unable to fork");
1450c06d385Sjwpoduska 	case 0:
146*165c5c6fSJohn Poduska 		do_child(fds[1], argv + optind, (size_t)(argc - optind));
1470c06d385Sjwpoduska 		break;
1480c06d385Sjwpoduska 	default:
1490c06d385Sjwpoduska 		break;
1500c06d385Sjwpoduska 	}
1510c06d385Sjwpoduska 
1520c06d385Sjwpoduska 	(void) close(fds[1]);
1530c06d385Sjwpoduska 
1540c06d385Sjwpoduska 	if (read(fds[0], &ret, sizeof (ret)) < 0)
1550c06d385Sjwpoduska 		err(EXIT_FAILURE, "failure waiting on child");
1560c06d385Sjwpoduska 
1570c06d385Sjwpoduska 	if (ret != 0)
1580c06d385Sjwpoduska 		return (ret);
1590c06d385Sjwpoduska 
1600c06d385Sjwpoduska 	(void) close(fds[0]);
1610c06d385Sjwpoduska 	(void) printf("%d\n", child);
1620c06d385Sjwpoduska 	return (0);
1630c06d385Sjwpoduska }
164