1eda14cbcSMatt Macy /* 2*180f8225SMatt Macy * This file is part of the ZFS Event Daemon (ZED). 3*180f8225SMatt Macy * 4eda14cbcSMatt Macy * Developed at Lawrence Livermore National Laboratory (LLNL-CODE-403049). 5eda14cbcSMatt Macy * Copyright (C) 2013-2014 Lawrence Livermore National Security, LLC. 6eda14cbcSMatt Macy * Refer to the ZoL git commit log for authoritative copyright attribution. 7eda14cbcSMatt Macy * 8eda14cbcSMatt Macy * The contents of this file are subject to the terms of the 9eda14cbcSMatt Macy * Common Development and Distribution License Version 1.0 (CDDL-1.0). 10eda14cbcSMatt Macy * You can obtain a copy of the license from the top-level file 11eda14cbcSMatt Macy * "OPENSOLARIS.LICENSE" or at <http://opensource.org/licenses/CDDL-1.0>. 12eda14cbcSMatt Macy * You may not use this file except in compliance with the license. 13eda14cbcSMatt Macy */ 14eda14cbcSMatt Macy 15eda14cbcSMatt Macy #include <assert.h> 16eda14cbcSMatt Macy #include <ctype.h> 17eda14cbcSMatt Macy #include <dirent.h> 18eda14cbcSMatt Macy #include <errno.h> 19eda14cbcSMatt Macy #include <fcntl.h> 20eda14cbcSMatt Macy #include <libgen.h> 21eda14cbcSMatt Macy #include <limits.h> 22eda14cbcSMatt Macy #include <stdio.h> 23eda14cbcSMatt Macy #include <stdlib.h> 24eda14cbcSMatt Macy #include <string.h> 25eda14cbcSMatt Macy #include <sys/stat.h> 26eda14cbcSMatt Macy #include <sys/uio.h> 27eda14cbcSMatt Macy #include <unistd.h> 28eda14cbcSMatt Macy #include "zed.h" 29eda14cbcSMatt Macy #include "zed_conf.h" 30eda14cbcSMatt Macy #include "zed_file.h" 31eda14cbcSMatt Macy #include "zed_log.h" 32eda14cbcSMatt Macy #include "zed_strings.h" 33eda14cbcSMatt Macy 34eda14cbcSMatt Macy /* 35eda14cbcSMatt Macy * Return a new configuration with default values. 36eda14cbcSMatt Macy */ 37eda14cbcSMatt Macy struct zed_conf * 38eda14cbcSMatt Macy zed_conf_create(void) 39eda14cbcSMatt Macy { 40eda14cbcSMatt Macy struct zed_conf *zcp; 41eda14cbcSMatt Macy 42eda14cbcSMatt Macy zcp = calloc(1, sizeof (*zcp)); 43eda14cbcSMatt Macy if (!zcp) 44eda14cbcSMatt Macy goto nomem; 45eda14cbcSMatt Macy 46eda14cbcSMatt Macy zcp->syslog_facility = LOG_DAEMON; 47eda14cbcSMatt Macy zcp->min_events = ZED_MIN_EVENTS; 48eda14cbcSMatt Macy zcp->max_events = ZED_MAX_EVENTS; 49eda14cbcSMatt Macy zcp->pid_fd = -1; 50eda14cbcSMatt Macy zcp->zedlets = NULL; /* created via zed_conf_scan_dir() */ 51eda14cbcSMatt Macy zcp->state_fd = -1; /* opened via zed_conf_open_state() */ 52eda14cbcSMatt Macy zcp->zfs_hdl = NULL; /* opened via zed_event_init() */ 53eda14cbcSMatt Macy zcp->zevent_fd = -1; /* opened via zed_event_init() */ 54eda14cbcSMatt Macy 55eda14cbcSMatt Macy if (!(zcp->conf_file = strdup(ZED_CONF_FILE))) 56eda14cbcSMatt Macy goto nomem; 57eda14cbcSMatt Macy 58eda14cbcSMatt Macy if (!(zcp->pid_file = strdup(ZED_PID_FILE))) 59eda14cbcSMatt Macy goto nomem; 60eda14cbcSMatt Macy 61eda14cbcSMatt Macy if (!(zcp->zedlet_dir = strdup(ZED_ZEDLET_DIR))) 62eda14cbcSMatt Macy goto nomem; 63eda14cbcSMatt Macy 64eda14cbcSMatt Macy if (!(zcp->state_file = strdup(ZED_STATE_FILE))) 65eda14cbcSMatt Macy goto nomem; 66eda14cbcSMatt Macy 67eda14cbcSMatt Macy return (zcp); 68eda14cbcSMatt Macy 69eda14cbcSMatt Macy nomem: 70eda14cbcSMatt Macy zed_log_die("Failed to create conf: %s", strerror(errno)); 71eda14cbcSMatt Macy return (NULL); 72eda14cbcSMatt Macy } 73eda14cbcSMatt Macy 74eda14cbcSMatt Macy /* 75eda14cbcSMatt Macy * Destroy the configuration [zcp]. 76eda14cbcSMatt Macy * 77eda14cbcSMatt Macy * Note: zfs_hdl & zevent_fd are destroyed via zed_event_fini(). 78eda14cbcSMatt Macy */ 79eda14cbcSMatt Macy void 80eda14cbcSMatt Macy zed_conf_destroy(struct zed_conf *zcp) 81eda14cbcSMatt Macy { 82eda14cbcSMatt Macy if (!zcp) 83eda14cbcSMatt Macy return; 84eda14cbcSMatt Macy 85eda14cbcSMatt Macy if (zcp->state_fd >= 0) { 86eda14cbcSMatt Macy if (close(zcp->state_fd) < 0) 87eda14cbcSMatt Macy zed_log_msg(LOG_WARNING, 88eda14cbcSMatt Macy "Failed to close state file \"%s\": %s", 89eda14cbcSMatt Macy zcp->state_file, strerror(errno)); 90eda14cbcSMatt Macy zcp->state_fd = -1; 91eda14cbcSMatt Macy } 92eda14cbcSMatt Macy if (zcp->pid_file) { 93eda14cbcSMatt Macy if ((unlink(zcp->pid_file) < 0) && (errno != ENOENT)) 94eda14cbcSMatt Macy zed_log_msg(LOG_WARNING, 95eda14cbcSMatt Macy "Failed to remove PID file \"%s\": %s", 96eda14cbcSMatt Macy zcp->pid_file, strerror(errno)); 97eda14cbcSMatt Macy } 98eda14cbcSMatt Macy if (zcp->pid_fd >= 0) { 99eda14cbcSMatt Macy if (close(zcp->pid_fd) < 0) 100eda14cbcSMatt Macy zed_log_msg(LOG_WARNING, 101eda14cbcSMatt Macy "Failed to close PID file \"%s\": %s", 102eda14cbcSMatt Macy zcp->pid_file, strerror(errno)); 103eda14cbcSMatt Macy zcp->pid_fd = -1; 104eda14cbcSMatt Macy } 105eda14cbcSMatt Macy if (zcp->conf_file) { 106eda14cbcSMatt Macy free(zcp->conf_file); 107eda14cbcSMatt Macy zcp->conf_file = NULL; 108eda14cbcSMatt Macy } 109eda14cbcSMatt Macy if (zcp->pid_file) { 110eda14cbcSMatt Macy free(zcp->pid_file); 111eda14cbcSMatt Macy zcp->pid_file = NULL; 112eda14cbcSMatt Macy } 113eda14cbcSMatt Macy if (zcp->zedlet_dir) { 114eda14cbcSMatt Macy free(zcp->zedlet_dir); 115eda14cbcSMatt Macy zcp->zedlet_dir = NULL; 116eda14cbcSMatt Macy } 117eda14cbcSMatt Macy if (zcp->state_file) { 118eda14cbcSMatt Macy free(zcp->state_file); 119eda14cbcSMatt Macy zcp->state_file = NULL; 120eda14cbcSMatt Macy } 121eda14cbcSMatt Macy if (zcp->zedlets) { 122eda14cbcSMatt Macy zed_strings_destroy(zcp->zedlets); 123eda14cbcSMatt Macy zcp->zedlets = NULL; 124eda14cbcSMatt Macy } 125eda14cbcSMatt Macy free(zcp); 126eda14cbcSMatt Macy } 127eda14cbcSMatt Macy 128eda14cbcSMatt Macy /* 129eda14cbcSMatt Macy * Display command-line help and exit. 130eda14cbcSMatt Macy * 131eda14cbcSMatt Macy * If [got_err] is 0, output to stdout and exit normally; 132eda14cbcSMatt Macy * otherwise, output to stderr and exit with a failure status. 133eda14cbcSMatt Macy */ 134eda14cbcSMatt Macy static void 135eda14cbcSMatt Macy _zed_conf_display_help(const char *prog, int got_err) 136eda14cbcSMatt Macy { 137eda14cbcSMatt Macy FILE *fp = got_err ? stderr : stdout; 138eda14cbcSMatt Macy int w1 = 4; /* width of leading whitespace */ 139eda14cbcSMatt Macy int w2 = 8; /* width of L-justified option field */ 140eda14cbcSMatt Macy 141eda14cbcSMatt Macy fprintf(fp, "Usage: %s [OPTION]...\n", (prog ? prog : "zed")); 142eda14cbcSMatt Macy fprintf(fp, "\n"); 143eda14cbcSMatt Macy fprintf(fp, "%*c%*s %s\n", w1, 0x20, -w2, "-h", 144eda14cbcSMatt Macy "Display help."); 145eda14cbcSMatt Macy fprintf(fp, "%*c%*s %s\n", w1, 0x20, -w2, "-L", 146eda14cbcSMatt Macy "Display license information."); 147eda14cbcSMatt Macy fprintf(fp, "%*c%*s %s\n", w1, 0x20, -w2, "-V", 148eda14cbcSMatt Macy "Display version information."); 149eda14cbcSMatt Macy fprintf(fp, "\n"); 150eda14cbcSMatt Macy fprintf(fp, "%*c%*s %s\n", w1, 0x20, -w2, "-v", 151eda14cbcSMatt Macy "Be verbose."); 152eda14cbcSMatt Macy fprintf(fp, "%*c%*s %s\n", w1, 0x20, -w2, "-f", 153eda14cbcSMatt Macy "Force daemon to run."); 154eda14cbcSMatt Macy fprintf(fp, "%*c%*s %s\n", w1, 0x20, -w2, "-F", 155eda14cbcSMatt Macy "Run daemon in the foreground."); 156eda14cbcSMatt Macy fprintf(fp, "%*c%*s %s\n", w1, 0x20, -w2, "-I", 157eda14cbcSMatt Macy "Idle daemon until kernel module is (re)loaded."); 158eda14cbcSMatt Macy fprintf(fp, "%*c%*s %s\n", w1, 0x20, -w2, "-M", 159eda14cbcSMatt Macy "Lock all pages in memory."); 160eda14cbcSMatt Macy fprintf(fp, "%*c%*s %s\n", w1, 0x20, -w2, "-P", 161eda14cbcSMatt Macy "$PATH for ZED to use (only used by ZTS)."); 162eda14cbcSMatt Macy fprintf(fp, "%*c%*s %s\n", w1, 0x20, -w2, "-Z", 163eda14cbcSMatt Macy "Zero state file."); 164eda14cbcSMatt Macy fprintf(fp, "\n"); 165eda14cbcSMatt Macy #if 0 166eda14cbcSMatt Macy fprintf(fp, "%*c%*s %s [%s]\n", w1, 0x20, -w2, "-c FILE", 167eda14cbcSMatt Macy "Read configuration from FILE.", ZED_CONF_FILE); 168eda14cbcSMatt Macy #endif 169eda14cbcSMatt Macy fprintf(fp, "%*c%*s %s [%s]\n", w1, 0x20, -w2, "-d DIR", 170eda14cbcSMatt Macy "Read enabled ZEDLETs from DIR.", ZED_ZEDLET_DIR); 171eda14cbcSMatt Macy fprintf(fp, "%*c%*s %s [%s]\n", w1, 0x20, -w2, "-p FILE", 172eda14cbcSMatt Macy "Write daemon's PID to FILE.", ZED_PID_FILE); 173eda14cbcSMatt Macy fprintf(fp, "%*c%*s %s [%s]\n", w1, 0x20, -w2, "-s FILE", 174eda14cbcSMatt Macy "Write daemon's state to FILE.", ZED_STATE_FILE); 175eda14cbcSMatt Macy fprintf(fp, "\n"); 176eda14cbcSMatt Macy 177eda14cbcSMatt Macy exit(got_err ? EXIT_FAILURE : EXIT_SUCCESS); 178eda14cbcSMatt Macy } 179eda14cbcSMatt Macy 180eda14cbcSMatt Macy /* 181eda14cbcSMatt Macy * Display license information to stdout and exit. 182eda14cbcSMatt Macy */ 183eda14cbcSMatt Macy static void 184eda14cbcSMatt Macy _zed_conf_display_license(void) 185eda14cbcSMatt Macy { 186eda14cbcSMatt Macy const char **pp; 187eda14cbcSMatt Macy const char *text[] = { 188eda14cbcSMatt Macy "The ZFS Event Daemon (ZED) is distributed under the terms of the", 189eda14cbcSMatt Macy " Common Development and Distribution License (CDDL-1.0)", 190eda14cbcSMatt Macy " <http://opensource.org/licenses/CDDL-1.0>.", 191eda14cbcSMatt Macy "", 192eda14cbcSMatt Macy "Developed at Lawrence Livermore National Laboratory" 193eda14cbcSMatt Macy " (LLNL-CODE-403049).", 194eda14cbcSMatt Macy "", 195eda14cbcSMatt Macy NULL 196eda14cbcSMatt Macy }; 197eda14cbcSMatt Macy 198eda14cbcSMatt Macy for (pp = text; *pp; pp++) 199eda14cbcSMatt Macy printf("%s\n", *pp); 200eda14cbcSMatt Macy 201eda14cbcSMatt Macy exit(EXIT_SUCCESS); 202eda14cbcSMatt Macy } 203eda14cbcSMatt Macy 204eda14cbcSMatt Macy /* 205eda14cbcSMatt Macy * Display version information to stdout and exit. 206eda14cbcSMatt Macy */ 207eda14cbcSMatt Macy static void 208eda14cbcSMatt Macy _zed_conf_display_version(void) 209eda14cbcSMatt Macy { 210eda14cbcSMatt Macy printf("%s-%s-%s\n", 211eda14cbcSMatt Macy ZFS_META_NAME, ZFS_META_VERSION, ZFS_META_RELEASE); 212eda14cbcSMatt Macy 213eda14cbcSMatt Macy exit(EXIT_SUCCESS); 214eda14cbcSMatt Macy } 215eda14cbcSMatt Macy 216eda14cbcSMatt Macy /* 217eda14cbcSMatt Macy * Copy the [path] string to the [resultp] ptr. 218eda14cbcSMatt Macy * If [path] is not an absolute path, prefix it with the current working dir. 219eda14cbcSMatt Macy * If [resultp] is non-null, free its existing string before assignment. 220eda14cbcSMatt Macy */ 221eda14cbcSMatt Macy static void 222eda14cbcSMatt Macy _zed_conf_parse_path(char **resultp, const char *path) 223eda14cbcSMatt Macy { 224eda14cbcSMatt Macy char buf[PATH_MAX]; 225eda14cbcSMatt Macy 226eda14cbcSMatt Macy assert(resultp != NULL); 227eda14cbcSMatt Macy assert(path != NULL); 228eda14cbcSMatt Macy 229eda14cbcSMatt Macy if (*resultp) 230eda14cbcSMatt Macy free(*resultp); 231eda14cbcSMatt Macy 232eda14cbcSMatt Macy if (path[0] == '/') { 233eda14cbcSMatt Macy *resultp = strdup(path); 234eda14cbcSMatt Macy } else if (!getcwd(buf, sizeof (buf))) { 235eda14cbcSMatt Macy zed_log_die("Failed to get current working dir: %s", 236eda14cbcSMatt Macy strerror(errno)); 237eda14cbcSMatt Macy } else if (strlcat(buf, "/", sizeof (buf)) >= sizeof (buf)) { 238eda14cbcSMatt Macy zed_log_die("Failed to copy path: %s", strerror(ENAMETOOLONG)); 239eda14cbcSMatt Macy } else if (strlcat(buf, path, sizeof (buf)) >= sizeof (buf)) { 240eda14cbcSMatt Macy zed_log_die("Failed to copy path: %s", strerror(ENAMETOOLONG)); 241eda14cbcSMatt Macy } else { 242eda14cbcSMatt Macy *resultp = strdup(buf); 243eda14cbcSMatt Macy } 244eda14cbcSMatt Macy if (!*resultp) 245eda14cbcSMatt Macy zed_log_die("Failed to copy path: %s", strerror(ENOMEM)); 246eda14cbcSMatt Macy } 247eda14cbcSMatt Macy 248eda14cbcSMatt Macy /* 249eda14cbcSMatt Macy * Parse the command-line options into the configuration [zcp]. 250eda14cbcSMatt Macy */ 251eda14cbcSMatt Macy void 252eda14cbcSMatt Macy zed_conf_parse_opts(struct zed_conf *zcp, int argc, char **argv) 253eda14cbcSMatt Macy { 254eda14cbcSMatt Macy const char * const opts = ":hLVc:d:p:P:s:vfFMZI"; 255eda14cbcSMatt Macy int opt; 256eda14cbcSMatt Macy 257eda14cbcSMatt Macy if (!zcp || !argv || !argv[0]) 258eda14cbcSMatt Macy zed_log_die("Failed to parse options: Internal error"); 259eda14cbcSMatt Macy 260eda14cbcSMatt Macy opterr = 0; /* suppress default getopt err msgs */ 261eda14cbcSMatt Macy 262eda14cbcSMatt Macy while ((opt = getopt(argc, argv, opts)) != -1) { 263eda14cbcSMatt Macy switch (opt) { 264eda14cbcSMatt Macy case 'h': 265eda14cbcSMatt Macy _zed_conf_display_help(argv[0], EXIT_SUCCESS); 266eda14cbcSMatt Macy break; 267eda14cbcSMatt Macy case 'L': 268eda14cbcSMatt Macy _zed_conf_display_license(); 269eda14cbcSMatt Macy break; 270eda14cbcSMatt Macy case 'V': 271eda14cbcSMatt Macy _zed_conf_display_version(); 272eda14cbcSMatt Macy break; 273eda14cbcSMatt Macy case 'c': 274eda14cbcSMatt Macy _zed_conf_parse_path(&zcp->conf_file, optarg); 275eda14cbcSMatt Macy break; 276eda14cbcSMatt Macy case 'd': 277eda14cbcSMatt Macy _zed_conf_parse_path(&zcp->zedlet_dir, optarg); 278eda14cbcSMatt Macy break; 279eda14cbcSMatt Macy case 'I': 280eda14cbcSMatt Macy zcp->do_idle = 1; 281eda14cbcSMatt Macy break; 282eda14cbcSMatt Macy case 'p': 283eda14cbcSMatt Macy _zed_conf_parse_path(&zcp->pid_file, optarg); 284eda14cbcSMatt Macy break; 285eda14cbcSMatt Macy case 'P': 286eda14cbcSMatt Macy _zed_conf_parse_path(&zcp->path, optarg); 287eda14cbcSMatt Macy break; 288eda14cbcSMatt Macy case 's': 289eda14cbcSMatt Macy _zed_conf_parse_path(&zcp->state_file, optarg); 290eda14cbcSMatt Macy break; 291eda14cbcSMatt Macy case 'v': 292eda14cbcSMatt Macy zcp->do_verbose = 1; 293eda14cbcSMatt Macy break; 294eda14cbcSMatt Macy case 'f': 295eda14cbcSMatt Macy zcp->do_force = 1; 296eda14cbcSMatt Macy break; 297eda14cbcSMatt Macy case 'F': 298eda14cbcSMatt Macy zcp->do_foreground = 1; 299eda14cbcSMatt Macy break; 300eda14cbcSMatt Macy case 'M': 301eda14cbcSMatt Macy zcp->do_memlock = 1; 302eda14cbcSMatt Macy break; 303eda14cbcSMatt Macy case 'Z': 304eda14cbcSMatt Macy zcp->do_zero = 1; 305eda14cbcSMatt Macy break; 306eda14cbcSMatt Macy case '?': 307eda14cbcSMatt Macy default: 308eda14cbcSMatt Macy if (optopt == '?') 309eda14cbcSMatt Macy _zed_conf_display_help(argv[0], EXIT_SUCCESS); 310eda14cbcSMatt Macy 311eda14cbcSMatt Macy fprintf(stderr, "%s: %s '-%c'\n\n", argv[0], 312eda14cbcSMatt Macy "Invalid option", optopt); 313eda14cbcSMatt Macy _zed_conf_display_help(argv[0], EXIT_FAILURE); 314eda14cbcSMatt Macy break; 315eda14cbcSMatt Macy } 316eda14cbcSMatt Macy } 317eda14cbcSMatt Macy } 318eda14cbcSMatt Macy 319eda14cbcSMatt Macy /* 320eda14cbcSMatt Macy * Parse the configuration file into the configuration [zcp]. 321eda14cbcSMatt Macy * 322eda14cbcSMatt Macy * FIXME: Not yet implemented. 323eda14cbcSMatt Macy */ 324eda14cbcSMatt Macy void 325eda14cbcSMatt Macy zed_conf_parse_file(struct zed_conf *zcp) 326eda14cbcSMatt Macy { 327eda14cbcSMatt Macy if (!zcp) 328eda14cbcSMatt Macy zed_log_die("Failed to parse config: %s", strerror(EINVAL)); 329eda14cbcSMatt Macy } 330eda14cbcSMatt Macy 331eda14cbcSMatt Macy /* 332eda14cbcSMatt Macy * Scan the [zcp] zedlet_dir for files to exec based on the event class. 333eda14cbcSMatt Macy * Files must be executable by user, but not writable by group or other. 334eda14cbcSMatt Macy * Dotfiles are ignored. 335eda14cbcSMatt Macy * 336eda14cbcSMatt Macy * Return 0 on success with an updated set of zedlets, 337eda14cbcSMatt Macy * or -1 on error with errno set. 338eda14cbcSMatt Macy * 339eda14cbcSMatt Macy * FIXME: Check if zedlet_dir and all parent dirs are secure. 340eda14cbcSMatt Macy */ 341eda14cbcSMatt Macy int 342eda14cbcSMatt Macy zed_conf_scan_dir(struct zed_conf *zcp) 343eda14cbcSMatt Macy { 344eda14cbcSMatt Macy zed_strings_t *zedlets; 345eda14cbcSMatt Macy DIR *dirp; 346eda14cbcSMatt Macy struct dirent *direntp; 347eda14cbcSMatt Macy char pathname[PATH_MAX]; 348eda14cbcSMatt Macy struct stat st; 349eda14cbcSMatt Macy int n; 350eda14cbcSMatt Macy 351eda14cbcSMatt Macy if (!zcp) { 352eda14cbcSMatt Macy errno = EINVAL; 353eda14cbcSMatt Macy zed_log_msg(LOG_ERR, "Failed to scan zedlet dir: %s", 354eda14cbcSMatt Macy strerror(errno)); 355eda14cbcSMatt Macy return (-1); 356eda14cbcSMatt Macy } 357eda14cbcSMatt Macy zedlets = zed_strings_create(); 358eda14cbcSMatt Macy if (!zedlets) { 359eda14cbcSMatt Macy errno = ENOMEM; 360eda14cbcSMatt Macy zed_log_msg(LOG_WARNING, "Failed to scan dir \"%s\": %s", 361eda14cbcSMatt Macy zcp->zedlet_dir, strerror(errno)); 362eda14cbcSMatt Macy return (-1); 363eda14cbcSMatt Macy } 364eda14cbcSMatt Macy dirp = opendir(zcp->zedlet_dir); 365eda14cbcSMatt Macy if (!dirp) { 366eda14cbcSMatt Macy int errno_bak = errno; 367eda14cbcSMatt Macy zed_log_msg(LOG_WARNING, "Failed to open dir \"%s\": %s", 368eda14cbcSMatt Macy zcp->zedlet_dir, strerror(errno)); 369eda14cbcSMatt Macy zed_strings_destroy(zedlets); 370eda14cbcSMatt Macy errno = errno_bak; 371eda14cbcSMatt Macy return (-1); 372eda14cbcSMatt Macy } 373eda14cbcSMatt Macy while ((direntp = readdir(dirp))) { 374eda14cbcSMatt Macy if (direntp->d_name[0] == '.') 375eda14cbcSMatt Macy continue; 376eda14cbcSMatt Macy 377eda14cbcSMatt Macy n = snprintf(pathname, sizeof (pathname), 378eda14cbcSMatt Macy "%s/%s", zcp->zedlet_dir, direntp->d_name); 379eda14cbcSMatt Macy if ((n < 0) || (n >= sizeof (pathname))) { 380eda14cbcSMatt Macy zed_log_msg(LOG_WARNING, "Failed to stat \"%s\": %s", 381eda14cbcSMatt Macy direntp->d_name, strerror(ENAMETOOLONG)); 382eda14cbcSMatt Macy continue; 383eda14cbcSMatt Macy } 384eda14cbcSMatt Macy if (stat(pathname, &st) < 0) { 385eda14cbcSMatt Macy zed_log_msg(LOG_WARNING, "Failed to stat \"%s\": %s", 386eda14cbcSMatt Macy pathname, strerror(errno)); 387eda14cbcSMatt Macy continue; 388eda14cbcSMatt Macy } 389eda14cbcSMatt Macy if (!S_ISREG(st.st_mode)) { 390eda14cbcSMatt Macy zed_log_msg(LOG_INFO, 391eda14cbcSMatt Macy "Ignoring \"%s\": not a regular file", 392eda14cbcSMatt Macy direntp->d_name); 393eda14cbcSMatt Macy continue; 394eda14cbcSMatt Macy } 395eda14cbcSMatt Macy if ((st.st_uid != 0) && !zcp->do_force) { 396eda14cbcSMatt Macy zed_log_msg(LOG_NOTICE, 397eda14cbcSMatt Macy "Ignoring \"%s\": not owned by root", 398eda14cbcSMatt Macy direntp->d_name); 399eda14cbcSMatt Macy continue; 400eda14cbcSMatt Macy } 401eda14cbcSMatt Macy if (!(st.st_mode & S_IXUSR)) { 402eda14cbcSMatt Macy zed_log_msg(LOG_INFO, 403eda14cbcSMatt Macy "Ignoring \"%s\": not executable by user", 404eda14cbcSMatt Macy direntp->d_name); 405eda14cbcSMatt Macy continue; 406eda14cbcSMatt Macy } 407eda14cbcSMatt Macy if ((st.st_mode & S_IWGRP) && !zcp->do_force) { 408eda14cbcSMatt Macy zed_log_msg(LOG_NOTICE, 409eda14cbcSMatt Macy "Ignoring \"%s\": writable by group", 410eda14cbcSMatt Macy direntp->d_name); 411eda14cbcSMatt Macy continue; 412eda14cbcSMatt Macy } 413eda14cbcSMatt Macy if ((st.st_mode & S_IWOTH) && !zcp->do_force) { 414eda14cbcSMatt Macy zed_log_msg(LOG_NOTICE, 415eda14cbcSMatt Macy "Ignoring \"%s\": writable by other", 416eda14cbcSMatt Macy direntp->d_name); 417eda14cbcSMatt Macy continue; 418eda14cbcSMatt Macy } 419eda14cbcSMatt Macy if (zed_strings_add(zedlets, NULL, direntp->d_name) < 0) { 420eda14cbcSMatt Macy zed_log_msg(LOG_WARNING, 421eda14cbcSMatt Macy "Failed to register \"%s\": %s", 422eda14cbcSMatt Macy direntp->d_name, strerror(errno)); 423eda14cbcSMatt Macy continue; 424eda14cbcSMatt Macy } 425eda14cbcSMatt Macy if (zcp->do_verbose) 426eda14cbcSMatt Macy zed_log_msg(LOG_INFO, 427eda14cbcSMatt Macy "Registered zedlet \"%s\"", direntp->d_name); 428eda14cbcSMatt Macy } 429eda14cbcSMatt Macy if (closedir(dirp) < 0) { 430eda14cbcSMatt Macy int errno_bak = errno; 431eda14cbcSMatt Macy zed_log_msg(LOG_WARNING, "Failed to close dir \"%s\": %s", 432eda14cbcSMatt Macy zcp->zedlet_dir, strerror(errno)); 433eda14cbcSMatt Macy zed_strings_destroy(zedlets); 434eda14cbcSMatt Macy errno = errno_bak; 435eda14cbcSMatt Macy return (-1); 436eda14cbcSMatt Macy } 437eda14cbcSMatt Macy if (zcp->zedlets) 438eda14cbcSMatt Macy zed_strings_destroy(zcp->zedlets); 439eda14cbcSMatt Macy 440eda14cbcSMatt Macy zcp->zedlets = zedlets; 441eda14cbcSMatt Macy return (0); 442eda14cbcSMatt Macy } 443eda14cbcSMatt Macy 444eda14cbcSMatt Macy /* 445eda14cbcSMatt Macy * Write the PID file specified in [zcp]. 446eda14cbcSMatt Macy * Return 0 on success, -1 on error. 447eda14cbcSMatt Macy * 448eda14cbcSMatt Macy * This must be called after fork()ing to become a daemon (so the correct PID 449eda14cbcSMatt Macy * is recorded), but before daemonization is complete and the parent process 450eda14cbcSMatt Macy * exits (for synchronization with systemd). 451eda14cbcSMatt Macy */ 452eda14cbcSMatt Macy int 453eda14cbcSMatt Macy zed_conf_write_pid(struct zed_conf *zcp) 454eda14cbcSMatt Macy { 455eda14cbcSMatt Macy const mode_t dirmode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH; 456eda14cbcSMatt Macy const mode_t filemode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; 457eda14cbcSMatt Macy char buf[PATH_MAX]; 458eda14cbcSMatt Macy int n; 459eda14cbcSMatt Macy char *p; 460eda14cbcSMatt Macy mode_t mask; 461eda14cbcSMatt Macy int rv; 462eda14cbcSMatt Macy 463eda14cbcSMatt Macy if (!zcp || !zcp->pid_file) { 464eda14cbcSMatt Macy errno = EINVAL; 465eda14cbcSMatt Macy zed_log_msg(LOG_ERR, "Failed to create PID file: %s", 466eda14cbcSMatt Macy strerror(errno)); 467eda14cbcSMatt Macy return (-1); 468eda14cbcSMatt Macy } 469eda14cbcSMatt Macy assert(zcp->pid_fd == -1); 470eda14cbcSMatt Macy /* 471eda14cbcSMatt Macy * Create PID file directory if needed. 472eda14cbcSMatt Macy */ 473eda14cbcSMatt Macy n = strlcpy(buf, zcp->pid_file, sizeof (buf)); 474eda14cbcSMatt Macy if (n >= sizeof (buf)) { 475eda14cbcSMatt Macy errno = ENAMETOOLONG; 476eda14cbcSMatt Macy zed_log_msg(LOG_ERR, "Failed to create PID file: %s", 477eda14cbcSMatt Macy strerror(errno)); 478eda14cbcSMatt Macy goto err; 479eda14cbcSMatt Macy } 480eda14cbcSMatt Macy p = strrchr(buf, '/'); 481eda14cbcSMatt Macy if (p) 482eda14cbcSMatt Macy *p = '\0'; 483eda14cbcSMatt Macy 484eda14cbcSMatt Macy if ((mkdirp(buf, dirmode) < 0) && (errno != EEXIST)) { 485eda14cbcSMatt Macy zed_log_msg(LOG_ERR, "Failed to create directory \"%s\": %s", 486eda14cbcSMatt Macy buf, strerror(errno)); 487eda14cbcSMatt Macy goto err; 488eda14cbcSMatt Macy } 489eda14cbcSMatt Macy /* 490eda14cbcSMatt Macy * Obtain PID file lock. 491eda14cbcSMatt Macy */ 492eda14cbcSMatt Macy mask = umask(0); 493eda14cbcSMatt Macy umask(mask | 022); 494eda14cbcSMatt Macy zcp->pid_fd = open(zcp->pid_file, (O_RDWR | O_CREAT), filemode); 495eda14cbcSMatt Macy umask(mask); 496eda14cbcSMatt Macy if (zcp->pid_fd < 0) { 497eda14cbcSMatt Macy zed_log_msg(LOG_ERR, "Failed to open PID file \"%s\": %s", 498eda14cbcSMatt Macy zcp->pid_file, strerror(errno)); 499eda14cbcSMatt Macy goto err; 500eda14cbcSMatt Macy } 501eda14cbcSMatt Macy rv = zed_file_lock(zcp->pid_fd); 502eda14cbcSMatt Macy if (rv < 0) { 503eda14cbcSMatt Macy zed_log_msg(LOG_ERR, "Failed to lock PID file \"%s\": %s", 504eda14cbcSMatt Macy zcp->pid_file, strerror(errno)); 505eda14cbcSMatt Macy goto err; 506eda14cbcSMatt Macy } else if (rv > 0) { 507eda14cbcSMatt Macy pid_t pid = zed_file_is_locked(zcp->pid_fd); 508eda14cbcSMatt Macy if (pid < 0) { 509eda14cbcSMatt Macy zed_log_msg(LOG_ERR, 510eda14cbcSMatt Macy "Failed to test lock on PID file \"%s\"", 511eda14cbcSMatt Macy zcp->pid_file); 512eda14cbcSMatt Macy } else if (pid > 0) { 513eda14cbcSMatt Macy zed_log_msg(LOG_ERR, 514eda14cbcSMatt Macy "Found PID %d bound to PID file \"%s\"", 515eda14cbcSMatt Macy pid, zcp->pid_file); 516eda14cbcSMatt Macy } else { 517eda14cbcSMatt Macy zed_log_msg(LOG_ERR, 518eda14cbcSMatt Macy "Inconsistent lock state on PID file \"%s\"", 519eda14cbcSMatt Macy zcp->pid_file); 520eda14cbcSMatt Macy } 521eda14cbcSMatt Macy goto err; 522eda14cbcSMatt Macy } 523eda14cbcSMatt Macy /* 524eda14cbcSMatt Macy * Write PID file. 525eda14cbcSMatt Macy */ 526eda14cbcSMatt Macy n = snprintf(buf, sizeof (buf), "%d\n", (int)getpid()); 527eda14cbcSMatt Macy if ((n < 0) || (n >= sizeof (buf))) { 528eda14cbcSMatt Macy errno = ERANGE; 529eda14cbcSMatt Macy zed_log_msg(LOG_ERR, "Failed to write PID file \"%s\": %s", 530eda14cbcSMatt Macy zcp->pid_file, strerror(errno)); 531eda14cbcSMatt Macy } else if (zed_file_write_n(zcp->pid_fd, buf, n) != n) { 532eda14cbcSMatt Macy zed_log_msg(LOG_ERR, "Failed to write PID file \"%s\": %s", 533eda14cbcSMatt Macy zcp->pid_file, strerror(errno)); 534eda14cbcSMatt Macy } else if (fdatasync(zcp->pid_fd) < 0) { 535eda14cbcSMatt Macy zed_log_msg(LOG_ERR, "Failed to sync PID file \"%s\": %s", 536eda14cbcSMatt Macy zcp->pid_file, strerror(errno)); 537eda14cbcSMatt Macy } else { 538eda14cbcSMatt Macy return (0); 539eda14cbcSMatt Macy } 540eda14cbcSMatt Macy 541eda14cbcSMatt Macy err: 542eda14cbcSMatt Macy if (zcp->pid_fd >= 0) { 543eda14cbcSMatt Macy (void) close(zcp->pid_fd); 544eda14cbcSMatt Macy zcp->pid_fd = -1; 545eda14cbcSMatt Macy } 546eda14cbcSMatt Macy return (-1); 547eda14cbcSMatt Macy } 548eda14cbcSMatt Macy 549eda14cbcSMatt Macy /* 550eda14cbcSMatt Macy * Open and lock the [zcp] state_file. 551eda14cbcSMatt Macy * Return 0 on success, -1 on error. 552eda14cbcSMatt Macy * 553eda14cbcSMatt Macy * FIXME: Move state information into kernel. 554eda14cbcSMatt Macy */ 555eda14cbcSMatt Macy int 556eda14cbcSMatt Macy zed_conf_open_state(struct zed_conf *zcp) 557eda14cbcSMatt Macy { 558eda14cbcSMatt Macy char dirbuf[PATH_MAX]; 559eda14cbcSMatt Macy mode_t dirmode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH; 560eda14cbcSMatt Macy int n; 561eda14cbcSMatt Macy char *p; 562eda14cbcSMatt Macy int rv; 563eda14cbcSMatt Macy 564eda14cbcSMatt Macy if (!zcp || !zcp->state_file) { 565eda14cbcSMatt Macy errno = EINVAL; 566eda14cbcSMatt Macy zed_log_msg(LOG_ERR, "Failed to open state file: %s", 567eda14cbcSMatt Macy strerror(errno)); 568eda14cbcSMatt Macy return (-1); 569eda14cbcSMatt Macy } 570eda14cbcSMatt Macy n = strlcpy(dirbuf, zcp->state_file, sizeof (dirbuf)); 571eda14cbcSMatt Macy if (n >= sizeof (dirbuf)) { 572eda14cbcSMatt Macy errno = ENAMETOOLONG; 573eda14cbcSMatt Macy zed_log_msg(LOG_WARNING, "Failed to open state file: %s", 574eda14cbcSMatt Macy strerror(errno)); 575eda14cbcSMatt Macy return (-1); 576eda14cbcSMatt Macy } 577eda14cbcSMatt Macy p = strrchr(dirbuf, '/'); 578eda14cbcSMatt Macy if (p) 579eda14cbcSMatt Macy *p = '\0'; 580eda14cbcSMatt Macy 581eda14cbcSMatt Macy if ((mkdirp(dirbuf, dirmode) < 0) && (errno != EEXIST)) { 582eda14cbcSMatt Macy zed_log_msg(LOG_WARNING, 583eda14cbcSMatt Macy "Failed to create directory \"%s\": %s", 584eda14cbcSMatt Macy dirbuf, strerror(errno)); 585eda14cbcSMatt Macy return (-1); 586eda14cbcSMatt Macy } 587eda14cbcSMatt Macy if (zcp->state_fd >= 0) { 588eda14cbcSMatt Macy if (close(zcp->state_fd) < 0) { 589eda14cbcSMatt Macy zed_log_msg(LOG_WARNING, 590eda14cbcSMatt Macy "Failed to close state file \"%s\": %s", 591eda14cbcSMatt Macy zcp->state_file, strerror(errno)); 592eda14cbcSMatt Macy return (-1); 593eda14cbcSMatt Macy } 594eda14cbcSMatt Macy } 595eda14cbcSMatt Macy if (zcp->do_zero) 596eda14cbcSMatt Macy (void) unlink(zcp->state_file); 597eda14cbcSMatt Macy 598eda14cbcSMatt Macy zcp->state_fd = open(zcp->state_file, 599eda14cbcSMatt Macy (O_RDWR | O_CREAT), (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)); 600eda14cbcSMatt Macy if (zcp->state_fd < 0) { 601eda14cbcSMatt Macy zed_log_msg(LOG_WARNING, "Failed to open state file \"%s\": %s", 602eda14cbcSMatt Macy zcp->state_file, strerror(errno)); 603eda14cbcSMatt Macy return (-1); 604eda14cbcSMatt Macy } 605eda14cbcSMatt Macy rv = zed_file_lock(zcp->state_fd); 606eda14cbcSMatt Macy if (rv < 0) { 607eda14cbcSMatt Macy zed_log_msg(LOG_WARNING, "Failed to lock state file \"%s\": %s", 608eda14cbcSMatt Macy zcp->state_file, strerror(errno)); 609eda14cbcSMatt Macy return (-1); 610eda14cbcSMatt Macy } 611eda14cbcSMatt Macy if (rv > 0) { 612eda14cbcSMatt Macy pid_t pid = zed_file_is_locked(zcp->state_fd); 613eda14cbcSMatt Macy if (pid < 0) { 614eda14cbcSMatt Macy zed_log_msg(LOG_WARNING, 615eda14cbcSMatt Macy "Failed to test lock on state file \"%s\"", 616eda14cbcSMatt Macy zcp->state_file); 617eda14cbcSMatt Macy } else if (pid > 0) { 618eda14cbcSMatt Macy zed_log_msg(LOG_WARNING, 619eda14cbcSMatt Macy "Found PID %d bound to state file \"%s\"", 620eda14cbcSMatt Macy pid, zcp->state_file); 621eda14cbcSMatt Macy } else { 622eda14cbcSMatt Macy zed_log_msg(LOG_WARNING, 623eda14cbcSMatt Macy "Inconsistent lock state on state file \"%s\"", 624eda14cbcSMatt Macy zcp->state_file); 625eda14cbcSMatt Macy } 626eda14cbcSMatt Macy return (-1); 627eda14cbcSMatt Macy } 628eda14cbcSMatt Macy return (0); 629eda14cbcSMatt Macy } 630eda14cbcSMatt Macy 631eda14cbcSMatt Macy /* 632eda14cbcSMatt Macy * Read the opened [zcp] state_file to obtain the eid & etime of the last event 633eda14cbcSMatt Macy * processed. Write the state from the last event to the [eidp] & [etime] args 634eda14cbcSMatt Macy * passed by reference. Note that etime[] is an array of size 2. 635eda14cbcSMatt Macy * Return 0 on success, -1 on error. 636eda14cbcSMatt Macy */ 637eda14cbcSMatt Macy int 638eda14cbcSMatt Macy zed_conf_read_state(struct zed_conf *zcp, uint64_t *eidp, int64_t etime[]) 639eda14cbcSMatt Macy { 640eda14cbcSMatt Macy ssize_t len; 641eda14cbcSMatt Macy struct iovec iov[3]; 642eda14cbcSMatt Macy ssize_t n; 643eda14cbcSMatt Macy 644eda14cbcSMatt Macy if (!zcp || !eidp || !etime) { 645eda14cbcSMatt Macy errno = EINVAL; 646eda14cbcSMatt Macy zed_log_msg(LOG_ERR, 647eda14cbcSMatt Macy "Failed to read state file: %s", strerror(errno)); 648eda14cbcSMatt Macy return (-1); 649eda14cbcSMatt Macy } 650eda14cbcSMatt Macy if (lseek(zcp->state_fd, 0, SEEK_SET) == (off_t)-1) { 651eda14cbcSMatt Macy zed_log_msg(LOG_WARNING, 652eda14cbcSMatt Macy "Failed to reposition state file offset: %s", 653eda14cbcSMatt Macy strerror(errno)); 654eda14cbcSMatt Macy return (-1); 655eda14cbcSMatt Macy } 656eda14cbcSMatt Macy len = 0; 657eda14cbcSMatt Macy iov[0].iov_base = eidp; 658eda14cbcSMatt Macy len += iov[0].iov_len = sizeof (*eidp); 659eda14cbcSMatt Macy iov[1].iov_base = &etime[0]; 660eda14cbcSMatt Macy len += iov[1].iov_len = sizeof (etime[0]); 661eda14cbcSMatt Macy iov[2].iov_base = &etime[1]; 662eda14cbcSMatt Macy len += iov[2].iov_len = sizeof (etime[1]); 663eda14cbcSMatt Macy 664eda14cbcSMatt Macy n = readv(zcp->state_fd, iov, 3); 665eda14cbcSMatt Macy if (n == 0) { 666eda14cbcSMatt Macy *eidp = 0; 667eda14cbcSMatt Macy } else if (n < 0) { 668eda14cbcSMatt Macy zed_log_msg(LOG_WARNING, 669eda14cbcSMatt Macy "Failed to read state file \"%s\": %s", 670eda14cbcSMatt Macy zcp->state_file, strerror(errno)); 671eda14cbcSMatt Macy return (-1); 672eda14cbcSMatt Macy } else if (n != len) { 673eda14cbcSMatt Macy errno = EIO; 674eda14cbcSMatt Macy zed_log_msg(LOG_WARNING, 675eda14cbcSMatt Macy "Failed to read state file \"%s\": Read %d of %d bytes", 676eda14cbcSMatt Macy zcp->state_file, n, len); 677eda14cbcSMatt Macy return (-1); 678eda14cbcSMatt Macy } 679eda14cbcSMatt Macy return (0); 680eda14cbcSMatt Macy } 681eda14cbcSMatt Macy 682eda14cbcSMatt Macy /* 683eda14cbcSMatt Macy * Write the [eid] & [etime] of the last processed event to the opened 684eda14cbcSMatt Macy * [zcp] state_file. Note that etime[] is an array of size 2. 685eda14cbcSMatt Macy * Return 0 on success, -1 on error. 686eda14cbcSMatt Macy */ 687eda14cbcSMatt Macy int 688eda14cbcSMatt Macy zed_conf_write_state(struct zed_conf *zcp, uint64_t eid, int64_t etime[]) 689eda14cbcSMatt Macy { 690eda14cbcSMatt Macy ssize_t len; 691eda14cbcSMatt Macy struct iovec iov[3]; 692eda14cbcSMatt Macy ssize_t n; 693eda14cbcSMatt Macy 694eda14cbcSMatt Macy if (!zcp) { 695eda14cbcSMatt Macy errno = EINVAL; 696eda14cbcSMatt Macy zed_log_msg(LOG_ERR, 697eda14cbcSMatt Macy "Failed to write state file: %s", strerror(errno)); 698eda14cbcSMatt Macy return (-1); 699eda14cbcSMatt Macy } 700eda14cbcSMatt Macy if (lseek(zcp->state_fd, 0, SEEK_SET) == (off_t)-1) { 701eda14cbcSMatt Macy zed_log_msg(LOG_WARNING, 702eda14cbcSMatt Macy "Failed to reposition state file offset: %s", 703eda14cbcSMatt Macy strerror(errno)); 704eda14cbcSMatt Macy return (-1); 705eda14cbcSMatt Macy } 706eda14cbcSMatt Macy len = 0; 707eda14cbcSMatt Macy iov[0].iov_base = &eid; 708eda14cbcSMatt Macy len += iov[0].iov_len = sizeof (eid); 709eda14cbcSMatt Macy iov[1].iov_base = &etime[0]; 710eda14cbcSMatt Macy len += iov[1].iov_len = sizeof (etime[0]); 711eda14cbcSMatt Macy iov[2].iov_base = &etime[1]; 712eda14cbcSMatt Macy len += iov[2].iov_len = sizeof (etime[1]); 713eda14cbcSMatt Macy 714eda14cbcSMatt Macy n = writev(zcp->state_fd, iov, 3); 715eda14cbcSMatt Macy if (n < 0) { 716eda14cbcSMatt Macy zed_log_msg(LOG_WARNING, 717eda14cbcSMatt Macy "Failed to write state file \"%s\": %s", 718eda14cbcSMatt Macy zcp->state_file, strerror(errno)); 719eda14cbcSMatt Macy return (-1); 720eda14cbcSMatt Macy } 721eda14cbcSMatt Macy if (n != len) { 722eda14cbcSMatt Macy errno = EIO; 723eda14cbcSMatt Macy zed_log_msg(LOG_WARNING, 724eda14cbcSMatt Macy "Failed to write state file \"%s\": Wrote %d of %d bytes", 725eda14cbcSMatt Macy zcp->state_file, n, len); 726eda14cbcSMatt Macy return (-1); 727eda14cbcSMatt Macy } 728eda14cbcSMatt Macy if (fdatasync(zcp->state_fd) < 0) { 729eda14cbcSMatt Macy zed_log_msg(LOG_WARNING, 730eda14cbcSMatt Macy "Failed to sync state file \"%s\": %s", 731eda14cbcSMatt Macy zcp->state_file, strerror(errno)); 732eda14cbcSMatt Macy return (-1); 733eda14cbcSMatt Macy } 734eda14cbcSMatt Macy return (0); 735eda14cbcSMatt Macy } 736