2 * This file is part of the ZFS Event Daemon (ZED)
3 * for ZFS on Linux (ZoL) <http://zfsonlinux.org/>.
4 * Developed at Lawrence Livermore National Laboratory (LLNL-CODE-403049).
5 * Copyright (C) 2013-2014 Lawrence Livermore National Security, LLC.
6 * Refer to the ZoL git commit log for authoritative copyright attribution.
8 * The contents of this file are subject to the terms of the
9 * Common Development and Distribution License Version 1.0 (CDDL-1.0).
10 * You can obtain a copy of the license from the top-level file
11 * "OPENSOLARIS.LICENSE" or at <http://opensource.org/licenses/CDDL-1.0>.
12 * You may not use this file except in compliance with the license.
27 #include "zed_strings.h"
29 #define ZEVENT_FILENO 3
32 * Create an environment string array for passing to execve() using the
33 * NAME=VALUE strings in container [zsp].
34 * Return a newly-allocated environment, or NULL on error.
37 _zed_exec_create_env(zed_strings_t
*zsp
)
48 num_ptrs
= zed_strings_count(zsp
) + 1;
49 buflen
= num_ptrs
* sizeof (char *);
50 for (q
= zed_strings_first(zsp
); q
; q
= zed_strings_next(zsp
))
51 buflen
+= strlen(q
) + 1;
53 buf
= calloc(1, buflen
);
58 p
= buf
+ (num_ptrs
* sizeof (char *));
60 for (q
= zed_strings_first(zsp
); q
; q
= zed_strings_next(zsp
)) {
68 assert(buf
+ buflen
== p
);
69 return ((char **)buf
);
73 * Fork a child process to handle event [eid]. The program [prog]
74 * in directory [dir] is executed with the environment [env].
76 * The file descriptor [zfd] is the zevent_fd used to track the
77 * current cursor location within the zevent nvlist.
80 _zed_exec_fork_child(uint64_t eid
, const char *dir
, const char *prog
,
95 n
= snprintf(path
, sizeof (path
), "%s/%s", dir
, prog
);
96 if ((n
< 0) || (n
>= sizeof (path
))) {
97 zed_log_msg(LOG_WARNING
,
98 "Failed to fork \"%s\" for eid=%llu: %s",
99 prog
, eid
, strerror(ENAMETOOLONG
));
104 zed_log_msg(LOG_WARNING
,
105 "Failed to fork \"%s\" for eid=%llu: %s",
106 prog
, eid
, strerror(errno
));
108 } else if (pid
== 0) {
110 if ((fd
= open("/dev/null", O_RDWR
)) != -1) {
111 (void) dup2(fd
, STDIN_FILENO
);
112 (void) dup2(fd
, STDOUT_FILENO
);
113 (void) dup2(fd
, STDERR_FILENO
);
115 (void) dup2(zfd
, ZEVENT_FILENO
);
116 zed_file_close_from(ZEVENT_FILENO
+ 1);
117 execle(path
, prog
, NULL
, env
);
123 zed_log_msg(LOG_INFO
, "Invoking \"%s\" eid=%llu pid=%d",
126 /* FIXME: Timeout rogue child processes with sigalarm? */
129 * Wait for child process using WNOHANG to limit
130 * the time spent waiting to 10 seconds (10,000ms).
132 for (n
= 0; n
< 1000; n
++) {
133 wpid
= waitpid(pid
, &status
, WNOHANG
);
134 if (wpid
== (pid_t
)-1) {
137 zed_log_msg(LOG_WARNING
,
138 "Failed to wait for \"%s\" eid=%llu pid=%d",
141 } else if (wpid
== 0) {
144 /* child still running */
146 t
.tv_nsec
= 10000000; /* 10ms */
147 (void) nanosleep(&t
, NULL
);
151 if (WIFEXITED(status
)) {
152 zed_log_msg(LOG_INFO
,
153 "Finished \"%s\" eid=%llu pid=%d exit=%d",
154 prog
, eid
, pid
, WEXITSTATUS(status
));
155 } else if (WIFSIGNALED(status
)) {
156 zed_log_msg(LOG_INFO
,
157 "Finished \"%s\" eid=%llu pid=%d sig=%d/%s",
158 prog
, eid
, pid
, WTERMSIG(status
),
159 strsignal(WTERMSIG(status
)));
161 zed_log_msg(LOG_INFO
,
162 "Finished \"%s\" eid=%llu pid=%d status=0x%X",
163 prog
, eid
, (unsigned int) status
);
169 * kill child process after 10 seconds
172 zed_log_msg(LOG_WARNING
, "Killing hung \"%s\" pid=%d",
174 (void) kill(pid
, SIGKILL
);
179 * Process the event [eid] by synchronously invoking all zedlets with a
180 * matching class prefix.
182 * Each executable in [zedlets] from the directory [dir] is matched against
183 * the event's [class], [subclass], and the "all" class (which matches
184 * all events). Every zedlet with a matching class prefix is invoked.
185 * The NAME=VALUE strings in [envs] will be passed to the zedlet as
186 * environment variables.
188 * The file descriptor [zfd] is the zevent_fd used to track the
189 * current cursor location within the zevent nvlist.
191 * Return 0 on success, -1 on error.
194 zed_exec_process(uint64_t eid
, const char *class, const char *subclass
,
195 const char *dir
, zed_strings_t
*zedlets
, zed_strings_t
*envs
, int zfd
)
197 const char *class_strings
[4];
198 const char *allclass
= "all";
204 if (!dir
|| !zedlets
|| !envs
|| zfd
< 0)
220 e
= _zed_exec_create_env(envs
);
222 for (z
= zed_strings_first(zedlets
); z
; z
= zed_strings_next(zedlets
)) {
223 for (csp
= class_strings
; *csp
; csp
++) {
225 if ((strncmp(z
, *csp
, n
) == 0) && !isalpha(z
[n
]))
226 _zed_exec_fork_child(eid
, dir
, z
, e
, zfd
);