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.
32 #include "zed_strings.h"
35 * Return a new configuration with default values.
42 zcp
= calloc(1, sizeof (*zcp
));
46 zcp
->syslog_facility
= LOG_DAEMON
;
47 zcp
->min_events
= ZED_MIN_EVENTS
;
48 zcp
->max_events
= ZED_MAX_EVENTS
;
50 zcp
->zedlets
= NULL
; /* created via zed_conf_scan_dir() */
51 zcp
->state_fd
= -1; /* opened via zed_conf_open_state() */
52 zcp
->zfs_hdl
= NULL
; /* opened via zed_event_init() */
53 zcp
->zevent_fd
= -1; /* opened via zed_event_init() */
55 if (!(zcp
->conf_file
= strdup(ZED_CONF_FILE
)))
58 if (!(zcp
->pid_file
= strdup(ZED_PID_FILE
)))
61 if (!(zcp
->zedlet_dir
= strdup(ZED_ZEDLET_DIR
)))
64 if (!(zcp
->state_file
= strdup(ZED_STATE_FILE
)))
70 zed_log_die("Failed to create conf: %s", strerror(errno
));
75 * Destroy the configuration [zcp].
77 * Note: zfs_hdl & zevent_fd are destroyed via zed_event_fini().
80 zed_conf_destroy(struct zed_conf
*zcp
)
85 if (zcp
->state_fd
>= 0) {
86 if (close(zcp
->state_fd
) < 0)
87 zed_log_msg(LOG_WARNING
,
88 "Failed to close state file \"%s\": %s",
89 zcp
->state_file
, strerror(errno
));
93 if ((unlink(zcp
->pid_file
) < 0) && (errno
!= ENOENT
))
94 zed_log_msg(LOG_WARNING
,
95 "Failed to remove PID file \"%s\": %s",
96 zcp
->pid_file
, strerror(errno
));
98 if (zcp
->pid_fd
>= 0) {
99 if (close(zcp
->pid_fd
) < 0)
100 zed_log_msg(LOG_WARNING
,
101 "Failed to close PID file \"%s\": %s",
102 zcp
->pid_file
, strerror(errno
));
105 if (zcp
->conf_file
) {
106 free(zcp
->conf_file
);
107 zcp
->conf_file
= NULL
;
111 zcp
->pid_file
= NULL
;
113 if (zcp
->zedlet_dir
) {
114 free(zcp
->zedlet_dir
);
115 zcp
->zedlet_dir
= NULL
;
117 if (zcp
->state_file
) {
118 free(zcp
->state_file
);
119 zcp
->state_file
= NULL
;
122 zed_strings_destroy(zcp
->zedlets
);
129 * Display command-line help and exit.
131 * If [got_err] is 0, output to stdout and exit normally;
132 * otherwise, output to stderr and exit with a failure status.
135 _zed_conf_display_help(const char *prog
, int got_err
)
137 FILE *fp
= got_err
? stderr
: stdout
;
138 int w1
= 4; /* width of leading whitespace */
139 int w2
= 8; /* width of L-justified option field */
141 fprintf(fp
, "Usage: %s [OPTION]...\n", (prog
? prog
: "zed"));
143 fprintf(fp
, "%*c%*s %s\n", w1
, 0x20, -w2
, "-h",
145 fprintf(fp
, "%*c%*s %s\n", w1
, 0x20, -w2
, "-L",
146 "Display license information.");
147 fprintf(fp
, "%*c%*s %s\n", w1
, 0x20, -w2
, "-V",
148 "Display version information.");
150 fprintf(fp
, "%*c%*s %s\n", w1
, 0x20, -w2
, "-v",
152 fprintf(fp
, "%*c%*s %s\n", w1
, 0x20, -w2
, "-f",
153 "Force daemon to run.");
154 fprintf(fp
, "%*c%*s %s\n", w1
, 0x20, -w2
, "-F",
155 "Run daemon in the foreground.");
156 fprintf(fp
, "%*c%*s %s\n", w1
, 0x20, -w2
, "-M",
157 "Lock all pages in memory.");
158 fprintf(fp
, "%*c%*s %s\n", w1
, 0x20, -w2
, "-Z",
162 fprintf(fp
, "%*c%*s %s [%s]\n", w1
, 0x20, -w2
, "-c FILE",
163 "Read configuration from FILE.", ZED_CONF_FILE
);
165 fprintf(fp
, "%*c%*s %s [%s]\n", w1
, 0x20, -w2
, "-d DIR",
166 "Read enabled ZEDLETs from DIR.", ZED_ZEDLET_DIR
);
167 fprintf(fp
, "%*c%*s %s [%s]\n", w1
, 0x20, -w2
, "-p FILE",
168 "Write daemon's PID to FILE.", ZED_PID_FILE
);
169 fprintf(fp
, "%*c%*s %s [%s]\n", w1
, 0x20, -w2
, "-s FILE",
170 "Write daemon's state to FILE.", ZED_STATE_FILE
);
173 exit(got_err
? EXIT_FAILURE
: EXIT_SUCCESS
);
177 * Display license information to stdout and exit.
180 _zed_conf_display_license(void)
183 const char *text
[] = {
184 "The ZFS Event Daemon (ZED) is distributed under the terms of the",
185 " Common Development and Distribution License (CDDL-1.0)",
186 " <http://opensource.org/licenses/CDDL-1.0>.",
188 "Developed at Lawrence Livermore National Laboratory"
189 " (LLNL-CODE-403049).",
194 for (pp
= text
; *pp
; pp
++)
201 * Display version information to stdout and exit.
204 _zed_conf_display_version(void)
207 ZFS_META_NAME
, ZFS_META_VERSION
, ZFS_META_RELEASE
);
213 * Copy the [path] string to the [resultp] ptr.
214 * If [path] is not an absolute path, prefix it with the current working dir.
215 * If [resultp] is non-null, free its existing string before assignment.
218 _zed_conf_parse_path(char **resultp
, const char *path
)
222 assert(resultp
!= NULL
);
223 assert(path
!= NULL
);
228 if (path
[0] == '/') {
229 *resultp
= strdup(path
);
230 } else if (!getcwd(buf
, sizeof (buf
))) {
231 zed_log_die("Failed to get current working dir: %s",
233 } else if (strlcat(buf
, "/", sizeof (buf
)) >= sizeof (buf
)) {
234 zed_log_die("Failed to copy path: %s", strerror(ENAMETOOLONG
));
235 } else if (strlcat(buf
, path
, sizeof (buf
)) >= sizeof (buf
)) {
236 zed_log_die("Failed to copy path: %s", strerror(ENAMETOOLONG
));
238 *resultp
= strdup(buf
);
241 zed_log_die("Failed to copy path: %s", strerror(ENOMEM
));
245 * Parse the command-line options into the configuration [zcp].
248 zed_conf_parse_opts(struct zed_conf
*zcp
, int argc
, char **argv
)
250 const char * const opts
= ":hLVc:d:p:s:vfFMZ";
253 if (!zcp
|| !argv
|| !argv
[0])
254 zed_log_die("Failed to parse options: Internal error");
256 opterr
= 0; /* suppress default getopt err msgs */
258 while ((opt
= getopt(argc
, argv
, opts
)) != -1) {
261 _zed_conf_display_help(argv
[0], EXIT_SUCCESS
);
264 _zed_conf_display_license();
267 _zed_conf_display_version();
270 _zed_conf_parse_path(&zcp
->conf_file
, optarg
);
273 _zed_conf_parse_path(&zcp
->zedlet_dir
, optarg
);
276 _zed_conf_parse_path(&zcp
->pid_file
, optarg
);
279 _zed_conf_parse_path(&zcp
->state_file
, optarg
);
288 zcp
->do_foreground
= 1;
299 _zed_conf_display_help(argv
[0], EXIT_SUCCESS
);
301 fprintf(stderr
, "%s: %s '-%c'\n\n", argv
[0],
302 "Invalid option", optopt
);
303 _zed_conf_display_help(argv
[0], EXIT_FAILURE
);
310 * Parse the configuration file into the configuration [zcp].
312 * FIXME: Not yet implemented.
315 zed_conf_parse_file(struct zed_conf
*zcp
)
318 zed_log_die("Failed to parse config: %s", strerror(EINVAL
));
322 * Scan the [zcp] zedlet_dir for files to exec based on the event class.
323 * Files must be executable by user, but not writable by group or other.
324 * Dotfiles are ignored.
326 * Return 0 on success with an updated set of zedlets,
327 * or -1 on error with errno set.
329 * FIXME: Check if zedlet_dir and all parent dirs are secure.
332 zed_conf_scan_dir(struct zed_conf
*zcp
)
334 zed_strings_t
*zedlets
;
336 struct dirent
*direntp
;
337 char pathname
[PATH_MAX
];
343 zed_log_msg(LOG_ERR
, "Failed to scan zedlet dir: %s",
347 zedlets
= zed_strings_create();
350 zed_log_msg(LOG_WARNING
, "Failed to scan dir \"%s\": %s",
351 zcp
->zedlet_dir
, strerror(errno
));
354 dirp
= opendir(zcp
->zedlet_dir
);
356 int errno_bak
= errno
;
357 zed_log_msg(LOG_WARNING
, "Failed to open dir \"%s\": %s",
358 zcp
->zedlet_dir
, strerror(errno
));
359 zed_strings_destroy(zedlets
);
363 while ((direntp
= readdir(dirp
))) {
364 if (direntp
->d_name
[0] == '.')
367 n
= snprintf(pathname
, sizeof (pathname
),
368 "%s/%s", zcp
->zedlet_dir
, direntp
->d_name
);
369 if ((n
< 0) || (n
>= sizeof (pathname
))) {
370 zed_log_msg(LOG_WARNING
, "Failed to stat \"%s\": %s",
371 direntp
->d_name
, strerror(ENAMETOOLONG
));
374 if (stat(pathname
, &st
) < 0) {
375 zed_log_msg(LOG_WARNING
, "Failed to stat \"%s\": %s",
376 pathname
, strerror(errno
));
379 if (!S_ISREG(st
.st_mode
)) {
380 zed_log_msg(LOG_INFO
,
381 "Ignoring \"%s\": not a regular file",
385 if ((st
.st_uid
!= 0) && !zcp
->do_force
) {
386 zed_log_msg(LOG_NOTICE
,
387 "Ignoring \"%s\": not owned by root",
391 if (!(st
.st_mode
& S_IXUSR
)) {
392 zed_log_msg(LOG_INFO
,
393 "Ignoring \"%s\": not executable by user",
397 if ((st
.st_mode
& S_IWGRP
) & !zcp
->do_force
) {
398 zed_log_msg(LOG_NOTICE
,
399 "Ignoring \"%s\": writable by group",
403 if ((st
.st_mode
& S_IWOTH
) & !zcp
->do_force
) {
404 zed_log_msg(LOG_NOTICE
,
405 "Ignoring \"%s\": writable by other",
409 if (zed_strings_add(zedlets
, NULL
, direntp
->d_name
) < 0) {
410 zed_log_msg(LOG_WARNING
,
411 "Failed to register \"%s\": %s",
412 direntp
->d_name
, strerror(errno
));
416 zed_log_msg(LOG_INFO
,
417 "Registered zedlet \"%s\"", direntp
->d_name
);
419 if (closedir(dirp
) < 0) {
420 int errno_bak
= errno
;
421 zed_log_msg(LOG_WARNING
, "Failed to close dir \"%s\": %s",
422 zcp
->zedlet_dir
, strerror(errno
));
423 zed_strings_destroy(zedlets
);
428 zed_strings_destroy(zcp
->zedlets
);
430 zcp
->zedlets
= zedlets
;
435 * Write the PID file specified in [zcp].
436 * Return 0 on success, -1 on error.
438 * This must be called after fork()ing to become a daemon (so the correct PID
439 * is recorded), but before daemonization is complete and the parent process
440 * exits (for synchronization with systemd).
443 zed_conf_write_pid(struct zed_conf
*zcp
)
445 const mode_t dirmode
= S_IRWXU
| S_IRGRP
| S_IXGRP
| S_IROTH
| S_IXOTH
;
446 const mode_t filemode
= S_IRUSR
| S_IWUSR
| S_IRGRP
| S_IROTH
;
453 if (!zcp
|| !zcp
->pid_file
) {
455 zed_log_msg(LOG_ERR
, "Failed to create PID file: %s",
459 assert(zcp
->pid_fd
== -1);
461 * Create PID file directory if needed.
463 n
= strlcpy(buf
, zcp
->pid_file
, sizeof (buf
));
464 if (n
>= sizeof (buf
)) {
465 errno
= ENAMETOOLONG
;
466 zed_log_msg(LOG_ERR
, "Failed to create PID file: %s",
470 p
= strrchr(buf
, '/');
474 if ((mkdirp(buf
, dirmode
) < 0) && (errno
!= EEXIST
)) {
475 zed_log_msg(LOG_ERR
, "Failed to create directory \"%s\": %s",
476 buf
, strerror(errno
));
480 * Obtain PID file lock.
484 zcp
->pid_fd
= open(zcp
->pid_file
, (O_RDWR
| O_CREAT
), filemode
);
486 if (zcp
->pid_fd
< 0) {
487 zed_log_msg(LOG_ERR
, "Failed to open PID file \"%s\": %s",
488 zcp
->pid_file
, strerror(errno
));
491 rv
= zed_file_lock(zcp
->pid_fd
);
493 zed_log_msg(LOG_ERR
, "Failed to lock PID file \"%s\": %s",
494 zcp
->pid_file
, strerror(errno
));
497 pid_t pid
= zed_file_is_locked(zcp
->pid_fd
);
500 "Failed to test lock on PID file \"%s\"",
502 } else if (pid
> 0) {
504 "Found PID %d bound to PID file \"%s\"",
508 "Inconsistent lock state on PID file \"%s\"",
516 n
= snprintf(buf
, sizeof (buf
), "%d\n", (int)getpid());
517 if ((n
< 0) || (n
>= sizeof (buf
))) {
519 zed_log_msg(LOG_ERR
, "Failed to write PID file \"%s\": %s",
520 zcp
->pid_file
, strerror(errno
));
521 } else if (zed_file_write_n(zcp
->pid_fd
, buf
, n
) != n
) {
522 zed_log_msg(LOG_ERR
, "Failed to write PID file \"%s\": %s",
523 zcp
->pid_file
, strerror(errno
));
524 } else if (fdatasync(zcp
->pid_fd
) < 0) {
525 zed_log_msg(LOG_ERR
, "Failed to sync PID file \"%s\": %s",
526 zcp
->pid_file
, strerror(errno
));
532 if (zcp
->pid_fd
>= 0) {
533 (void) close(zcp
->pid_fd
);
540 * Open and lock the [zcp] state_file.
541 * Return 0 on success, -1 on error.
543 * FIXME: Move state information into kernel.
546 zed_conf_open_state(struct zed_conf
*zcp
)
548 char dirbuf
[PATH_MAX
];
549 mode_t dirmode
= S_IRWXU
| S_IRGRP
| S_IXGRP
| S_IROTH
| S_IXOTH
;
554 if (!zcp
|| !zcp
->state_file
) {
556 zed_log_msg(LOG_ERR
, "Failed to open state file: %s",
560 n
= strlcpy(dirbuf
, zcp
->state_file
, sizeof (dirbuf
));
561 if (n
>= sizeof (dirbuf
)) {
562 errno
= ENAMETOOLONG
;
563 zed_log_msg(LOG_WARNING
, "Failed to open state file: %s",
567 p
= strrchr(dirbuf
, '/');
571 if ((mkdirp(dirbuf
, dirmode
) < 0) && (errno
!= EEXIST
)) {
572 zed_log_msg(LOG_WARNING
,
573 "Failed to create directory \"%s\": %s",
574 dirbuf
, strerror(errno
));
577 if (zcp
->state_fd
>= 0) {
578 if (close(zcp
->state_fd
) < 0) {
579 zed_log_msg(LOG_WARNING
,
580 "Failed to close state file \"%s\": %s",
581 zcp
->state_file
, strerror(errno
));
586 (void) unlink(zcp
->state_file
);
588 zcp
->state_fd
= open(zcp
->state_file
,
589 (O_RDWR
| O_CREAT
), (S_IRUSR
| S_IWUSR
| S_IRGRP
| S_IROTH
));
590 if (zcp
->state_fd
< 0) {
591 zed_log_msg(LOG_WARNING
, "Failed to open state file \"%s\": %s",
592 zcp
->state_file
, strerror(errno
));
595 rv
= zed_file_lock(zcp
->state_fd
);
597 zed_log_msg(LOG_WARNING
, "Failed to lock state file \"%s\": %s",
598 zcp
->state_file
, strerror(errno
));
602 pid_t pid
= zed_file_is_locked(zcp
->state_fd
);
604 zed_log_msg(LOG_WARNING
,
605 "Failed to test lock on state file \"%s\"",
607 } else if (pid
> 0) {
608 zed_log_msg(LOG_WARNING
,
609 "Found PID %d bound to state file \"%s\"",
610 pid
, zcp
->state_file
);
612 zed_log_msg(LOG_WARNING
,
613 "Inconsistent lock state on state file \"%s\"",
622 * Read the opened [zcp] state_file to obtain the eid & etime of the last event
623 * processed. Write the state from the last event to the [eidp] & [etime] args
624 * passed by reference. Note that etime[] is an array of size 2.
625 * Return 0 on success, -1 on error.
628 zed_conf_read_state(struct zed_conf
*zcp
, uint64_t *eidp
, int64_t etime
[])
634 if (!zcp
|| !eidp
|| !etime
) {
637 "Failed to read state file: %s", strerror(errno
));
640 if (lseek(zcp
->state_fd
, 0, SEEK_SET
) == (off_t
)-1) {
641 zed_log_msg(LOG_WARNING
,
642 "Failed to reposition state file offset: %s",
647 iov
[0].iov_base
= eidp
;
648 len
+= iov
[0].iov_len
= sizeof (*eidp
);
649 iov
[1].iov_base
= &etime
[0];
650 len
+= iov
[1].iov_len
= sizeof (etime
[0]);
651 iov
[2].iov_base
= &etime
[1];
652 len
+= iov
[2].iov_len
= sizeof (etime
[1]);
654 n
= readv(zcp
->state_fd
, iov
, 3);
658 zed_log_msg(LOG_WARNING
,
659 "Failed to read state file \"%s\": %s",
660 zcp
->state_file
, strerror(errno
));
662 } else if (n
!= len
) {
664 zed_log_msg(LOG_WARNING
,
665 "Failed to read state file \"%s\": Read %d of %d bytes",
666 zcp
->state_file
, n
, len
);
673 * Write the [eid] & [etime] of the last processed event to the opened
674 * [zcp] state_file. Note that etime[] is an array of size 2.
675 * Return 0 on success, -1 on error.
678 zed_conf_write_state(struct zed_conf
*zcp
, uint64_t eid
, int64_t etime
[])
687 "Failed to write state file: %s", strerror(errno
));
690 if (lseek(zcp
->state_fd
, 0, SEEK_SET
) == (off_t
)-1) {
691 zed_log_msg(LOG_WARNING
,
692 "Failed to reposition state file offset: %s",
697 iov
[0].iov_base
= &eid
;
698 len
+= iov
[0].iov_len
= sizeof (eid
);
699 iov
[1].iov_base
= &etime
[0];
700 len
+= iov
[1].iov_len
= sizeof (etime
[0]);
701 iov
[2].iov_base
= &etime
[1];
702 len
+= iov
[2].iov_len
= sizeof (etime
[1]);
704 n
= writev(zcp
->state_fd
, iov
, 3);
706 zed_log_msg(LOG_WARNING
,
707 "Failed to write state file \"%s\": %s",
708 zcp
->state_file
, strerror(errno
));
713 zed_log_msg(LOG_WARNING
,
714 "Failed to write state file \"%s\": Wrote %d of %d bytes",
715 zcp
->state_file
, n
, len
);
718 if (fdatasync(zcp
->state_fd
) < 0) {
719 zed_log_msg(LOG_WARNING
,
720 "Failed to sync state file \"%s\": %s",
721 zcp
->state_file
, strerror(errno
));