1 // SPDX-License-Identifier: CDDL-1.0 2 /* 3 * This file is part of the ZFS Event Daemon (ZED). 4 * 5 * Developed at Lawrence Livermore National Laboratory (LLNL-CODE-403049). 6 * Copyright (C) 2013-2014 Lawrence Livermore National Security, LLC. 7 * Refer to the OpenZFS git commit log for authoritative copyright attribution. 8 * 9 * The contents of this file are subject to the terms of the 10 * Common Development and Distribution License Version 1.0 (CDDL-1.0). 11 * You can obtain a copy of the license from the top-level file 12 * "OPENSOLARIS.LICENSE" or at <http://opensource.org/licenses/CDDL-1.0>. 13 * You may not use this file except in compliance with the license. 14 */ 15 16 #include <assert.h> 17 #include <ctype.h> 18 #include <errno.h> 19 #include <fcntl.h> 20 #include <stdlib.h> 21 #include <string.h> 22 #include <stddef.h> 23 #include <sys/avl.h> 24 #include <sys/resource.h> 25 #include <sys/stat.h> 26 #include <sys/wait.h> 27 #include <time.h> 28 #include <unistd.h> 29 #include <pthread.h> 30 #include <signal.h> 31 32 #include "zed_exec.h" 33 #include "zed_log.h" 34 #include "zed_strings.h" 35 36 #define ZEVENT_FILENO 3 37 38 struct launched_process_node { 39 avl_node_t node; 40 pid_t pid; 41 uint64_t eid; 42 char *name; 43 }; 44 45 static int 46 _launched_process_node_compare(const void *x1, const void *x2) 47 { 48 pid_t p1; 49 pid_t p2; 50 51 assert(x1 != NULL); 52 assert(x2 != NULL); 53 54 p1 = ((const struct launched_process_node *) x1)->pid; 55 p2 = ((const struct launched_process_node *) x2)->pid; 56 57 if (p1 < p2) 58 return (-1); 59 else if (p1 == p2) 60 return (0); 61 else 62 return (1); 63 } 64 65 static pthread_t _reap_children_tid = (pthread_t)-1; 66 static volatile boolean_t _reap_children_stop; 67 static avl_tree_t _launched_processes; 68 static pthread_mutex_t _launched_processes_lock = PTHREAD_MUTEX_INITIALIZER; 69 static int16_t _launched_processes_limit; 70 71 /* 72 * Create an environment string array for passing to execve() using the 73 * NAME=VALUE strings in container [zsp]. 74 * Return a newly-allocated environment, or NULL on error. 75 */ 76 static char ** 77 _zed_exec_create_env(zed_strings_t *zsp) 78 { 79 int num_ptrs; 80 int buflen; 81 char *buf; 82 char **pp; 83 char *p; 84 const char *q; 85 int i; 86 int len; 87 88 num_ptrs = zed_strings_count(zsp) + 1; 89 buflen = num_ptrs * sizeof (char *); 90 for (q = zed_strings_first(zsp); q; q = zed_strings_next(zsp)) 91 buflen += strlen(q) + 1; 92 93 buf = calloc(1, buflen); 94 if (!buf) 95 return (NULL); 96 97 pp = (char **)buf; 98 p = buf + (num_ptrs * sizeof (char *)); 99 i = 0; 100 for (q = zed_strings_first(zsp); q; q = zed_strings_next(zsp)) { 101 pp[i] = p; 102 len = strlen(q) + 1; 103 memcpy(p, q, len); 104 p += len; 105 i++; 106 } 107 pp[i] = NULL; 108 assert(buf + buflen == p); 109 return ((char **)buf); 110 } 111 112 /* 113 * Fork a child process to handle event [eid]. The program [prog] 114 * in directory [dir] is executed with the environment [env]. 115 * 116 * The file descriptor [zfd] is the zevent_fd used to track the 117 * current cursor location within the zevent nvlist. 118 */ 119 static void 120 _zed_exec_fork_child(uint64_t eid, const char *dir, const char *prog, 121 char *env[], int zfd, boolean_t in_foreground) 122 { 123 char path[PATH_MAX]; 124 int n; 125 pid_t pid; 126 int fd; 127 struct launched_process_node *node; 128 sigset_t mask; 129 struct timespec launch_timeout = 130 { .tv_sec = 0, .tv_nsec = 200 * 1000 * 1000, }; 131 132 assert(dir != NULL); 133 assert(prog != NULL); 134 assert(env != NULL); 135 assert(zfd >= 0); 136 137 while (__atomic_load_n(&_launched_processes_limit, 138 __ATOMIC_SEQ_CST) <= 0) 139 (void) nanosleep(&launch_timeout, NULL); 140 141 n = snprintf(path, sizeof (path), "%s/%s", dir, prog); 142 if ((n < 0) || (n >= sizeof (path))) { 143 zed_log_msg(LOG_WARNING, 144 "Failed to fork \"%s\" for eid=%llu: %s", 145 prog, eid, strerror(ENAMETOOLONG)); 146 return; 147 } 148 (void) pthread_mutex_lock(&_launched_processes_lock); 149 pid = fork(); 150 if (pid < 0) { 151 (void) pthread_mutex_unlock(&_launched_processes_lock); 152 zed_log_msg(LOG_WARNING, 153 "Failed to fork \"%s\" for eid=%llu: %s", 154 prog, eid, strerror(errno)); 155 return; 156 } else if (pid == 0) { 157 (void) sigemptyset(&mask); 158 (void) sigprocmask(SIG_SETMASK, &mask, NULL); 159 160 (void) umask(022); 161 if (in_foreground && /* we're already devnulled if daemonised */ 162 (fd = open("/dev/null", O_RDWR | O_CLOEXEC)) != -1) { 163 (void) dup2(fd, STDIN_FILENO); 164 (void) dup2(fd, STDOUT_FILENO); 165 (void) dup2(fd, STDERR_FILENO); 166 } 167 (void) dup2(zfd, ZEVENT_FILENO); 168 execle(path, prog, NULL, env); 169 _exit(127); 170 } 171 172 /* parent process */ 173 174 node = calloc(1, sizeof (*node)); 175 if (node) { 176 node->pid = pid; 177 node->eid = eid; 178 node->name = strdup(prog); 179 if (node->name == NULL) { 180 perror("strdup"); 181 exit(EXIT_FAILURE); 182 } 183 184 avl_add(&_launched_processes, node); 185 } 186 (void) pthread_mutex_unlock(&_launched_processes_lock); 187 188 __atomic_sub_fetch(&_launched_processes_limit, 1, __ATOMIC_SEQ_CST); 189 zed_log_msg(LOG_INFO, "Invoking \"%s\" eid=%llu pid=%d", 190 prog, eid, pid); 191 } 192 193 static void 194 _nop(int sig) 195 { 196 (void) sig; 197 } 198 199 static void 200 wait_for_children(boolean_t do_pause, boolean_t wait) 201 { 202 pid_t pid; 203 struct rusage usage; 204 int status; 205 struct launched_process_node node, *pnode; 206 207 for (_reap_children_stop = B_FALSE; !_reap_children_stop; ) { 208 (void) pthread_mutex_lock(&_launched_processes_lock); 209 pid = wait4(0, &status, wait ? 0 : WNOHANG, &usage); 210 if (pid == 0 || pid == (pid_t)-1) { 211 (void) pthread_mutex_unlock(&_launched_processes_lock); 212 if ((pid == 0) || (errno == ECHILD)) { 213 if (do_pause) 214 pause(); 215 } else if (errno != EINTR) 216 zed_log_msg(LOG_WARNING, 217 "Failed to wait for children: %s", 218 strerror(errno)); 219 if (!do_pause) 220 return; 221 222 } else { 223 memset(&node, 0, sizeof (node)); 224 node.pid = pid; 225 pnode = avl_find(&_launched_processes, &node, NULL); 226 if (pnode) { 227 memcpy(&node, pnode, sizeof (node)); 228 229 avl_remove(&_launched_processes, pnode); 230 free(pnode); 231 } 232 (void) pthread_mutex_unlock(&_launched_processes_lock); 233 __atomic_add_fetch(&_launched_processes_limit, 1, 234 __ATOMIC_SEQ_CST); 235 236 usage.ru_utime.tv_sec += usage.ru_stime.tv_sec; 237 usage.ru_utime.tv_usec += usage.ru_stime.tv_usec; 238 usage.ru_utime.tv_sec += 239 usage.ru_utime.tv_usec / (1000 * 1000); 240 usage.ru_utime.tv_usec %= 1000 * 1000; 241 242 if (WIFEXITED(status)) { 243 zed_log_msg(LOG_INFO, 244 "Finished \"%s\" eid=%llu pid=%d " 245 "time=%llu.%06us exit=%d", 246 node.name, node.eid, pid, 247 (unsigned long long) usage.ru_utime.tv_sec, 248 (unsigned int) usage.ru_utime.tv_usec, 249 WEXITSTATUS(status)); 250 } else if (WIFSIGNALED(status)) { 251 zed_log_msg(LOG_INFO, 252 "Finished \"%s\" eid=%llu pid=%d " 253 "time=%llu.%06us sig=%d/%s", 254 node.name, node.eid, pid, 255 (unsigned long long) usage.ru_utime.tv_sec, 256 (unsigned int) usage.ru_utime.tv_usec, 257 WTERMSIG(status), 258 strsignal(WTERMSIG(status))); 259 } else { 260 zed_log_msg(LOG_INFO, 261 "Finished \"%s\" eid=%llu pid=%d " 262 "time=%llu.%06us status=0x%X", 263 node.name, node.eid, pid, 264 (unsigned long long) usage.ru_utime.tv_sec, 265 (unsigned int) usage.ru_utime.tv_usec, 266 (unsigned int) status); 267 } 268 269 free(node.name); 270 } 271 } 272 273 } 274 275 static void * 276 _reap_children(void *arg) 277 { 278 (void) arg; 279 struct sigaction sa = {}; 280 281 (void) sigfillset(&sa.sa_mask); 282 (void) sigdelset(&sa.sa_mask, SIGCHLD); 283 (void) pthread_sigmask(SIG_SETMASK, &sa.sa_mask, NULL); 284 285 (void) sigemptyset(&sa.sa_mask); 286 sa.sa_handler = _nop; 287 sa.sa_flags = SA_NOCLDSTOP; 288 (void) sigaction(SIGCHLD, &sa, NULL); 289 290 wait_for_children(B_TRUE, B_FALSE); 291 292 return (NULL); 293 } 294 295 void 296 zed_exec_fini(void) 297 { 298 struct launched_process_node *node; 299 void *ck = NULL; 300 301 if (_reap_children_tid == (pthread_t)-1) 302 return; 303 304 _reap_children_stop = B_TRUE; 305 (void) pthread_kill(_reap_children_tid, SIGCHLD); 306 (void) pthread_join(_reap_children_tid, NULL); 307 308 while ((node = avl_destroy_nodes(&_launched_processes, &ck)) != NULL) { 309 free(node->name); 310 free(node); 311 } 312 avl_destroy(&_launched_processes); 313 314 (void) pthread_mutex_destroy(&_launched_processes_lock); 315 (void) pthread_mutex_init(&_launched_processes_lock, NULL); 316 317 _reap_children_tid = (pthread_t)-1; 318 } 319 320 /* 321 * Check if the zedlet name indicates if it is a synchronous zedlet 322 * 323 * Synchronous zedlets have a "-sync-" immediately following the event name in 324 * their zedlet filename, like: 325 * 326 * EVENT_NAME-sync-ZEDLETNAME.sh 327 * 328 * For example, if you wanted a synchronous statechange script: 329 * 330 * statechange-sync-myzedlet.sh 331 * 332 * Synchronous zedlets are guaranteed to be the only zedlet running. No other 333 * zedlets may run in parallel with a synchronous zedlet. A synchronous 334 * zedlet will wait for all previously spawned zedlets to finish before running. 335 * Users should be careful to only use synchronous zedlets when needed, since 336 * they decrease parallelism. 337 */ 338 static boolean_t 339 zedlet_is_sync(const char *zedlet, const char *event) 340 { 341 const char *sync_str = "-sync-"; 342 size_t sync_str_len; 343 size_t zedlet_len; 344 size_t event_len; 345 346 sync_str_len = strlen(sync_str); 347 zedlet_len = strlen(zedlet); 348 event_len = strlen(event); 349 350 if (event_len + sync_str_len >= zedlet_len) 351 return (B_FALSE); 352 353 if (strncmp(&zedlet[event_len], sync_str, sync_str_len) == 0) 354 return (B_TRUE); 355 356 return (B_FALSE); 357 } 358 359 /* 360 * Process the event [eid] by synchronously invoking all zedlets with a 361 * matching class prefix. 362 * 363 * Each executable in [zcp->zedlets] from the directory [zcp->zedlet_dir] 364 * is matched against the event's [class], [subclass], and the "all" class 365 * (which matches all events). 366 * Every zedlet with a matching class prefix is invoked. 367 * The NAME=VALUE strings in [envs] will be passed to the zedlet as 368 * environment variables. 369 * 370 * The file descriptor [zcp->zevent_fd] is the zevent_fd used to track the 371 * current cursor location within the zevent nvlist. 372 * 373 * Return 0 on success, -1 on error. 374 */ 375 int 376 zed_exec_process(uint64_t eid, const char *class, const char *subclass, 377 struct zed_conf *zcp, zed_strings_t *envs) 378 { 379 const char *class_strings[4]; 380 const char *allclass = "all"; 381 const char **csp; 382 const char *z; 383 char **e; 384 int n; 385 386 if (!zcp->zedlet_dir || !zcp->zedlets || !envs || zcp->zevent_fd < 0) 387 return (-1); 388 389 if (_reap_children_tid == (pthread_t)-1) { 390 _launched_processes_limit = zcp->max_jobs; 391 392 if (pthread_create(&_reap_children_tid, NULL, 393 _reap_children, NULL) != 0) 394 return (-1); 395 pthread_setname_np(_reap_children_tid, "reap ZEDLETs"); 396 397 avl_create(&_launched_processes, _launched_process_node_compare, 398 sizeof (struct launched_process_node), 399 offsetof(struct launched_process_node, node)); 400 } 401 402 csp = class_strings; 403 404 if (class) 405 *csp++ = class; 406 407 if (subclass) 408 *csp++ = subclass; 409 410 if (allclass) 411 *csp++ = allclass; 412 413 *csp = NULL; 414 415 e = _zed_exec_create_env(envs); 416 417 for (z = zed_strings_first(zcp->zedlets); z; 418 z = zed_strings_next(zcp->zedlets)) { 419 for (csp = class_strings; *csp; csp++) { 420 n = strlen(*csp); 421 if ((strncmp(z, *csp, n) == 0) && !isalpha(z[n])) { 422 boolean_t is_sync = zedlet_is_sync(z, *csp); 423 424 if (is_sync) { 425 /* 426 * Wait for previous zedlets to 427 * finish 428 */ 429 wait_for_children(B_FALSE, B_TRUE); 430 } 431 432 _zed_exec_fork_child(eid, zcp->zedlet_dir, 433 z, e, zcp->zevent_fd, zcp->do_foreground); 434 435 if (is_sync) { 436 /* 437 * Wait for sync zedlet we just launched 438 * to finish. 439 */ 440 wait_for_children(B_FALSE, B_TRUE); 441 } 442 } 443 } 444 } 445 free(e); 446 return (0); 447 } 448