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