]>
git.proxmox.com Git - mirror_zfs.git/blob - cmd/zed/zed_conf.c
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
, "-P",
159 "$PATH for ZED to use (only used by ZTS).");
160 fprintf(fp
, "%*c%*s %s\n", w1
, 0x20, -w2
, "-Z",
164 fprintf(fp
, "%*c%*s %s [%s]\n", w1
, 0x20, -w2
, "-c FILE",
165 "Read configuration from FILE.", ZED_CONF_FILE
);
167 fprintf(fp
, "%*c%*s %s [%s]\n", w1
, 0x20, -w2
, "-d DIR",
168 "Read enabled ZEDLETs from DIR.", ZED_ZEDLET_DIR
);
169 fprintf(fp
, "%*c%*s %s [%s]\n", w1
, 0x20, -w2
, "-p FILE",
170 "Write daemon's PID to FILE.", ZED_PID_FILE
);
171 fprintf(fp
, "%*c%*s %s [%s]\n", w1
, 0x20, -w2
, "-s FILE",
172 "Write daemon's state to FILE.", ZED_STATE_FILE
);
175 exit(got_err
? EXIT_FAILURE
: EXIT_SUCCESS
);
179 * Display license information to stdout and exit.
182 _zed_conf_display_license(void)
185 const char *text
[] = {
186 "The ZFS Event Daemon (ZED) is distributed under the terms of the",
187 " Common Development and Distribution License (CDDL-1.0)",
188 " <http://opensource.org/licenses/CDDL-1.0>.",
190 "Developed at Lawrence Livermore National Laboratory"
191 " (LLNL-CODE-403049).",
196 for (pp
= text
; *pp
; pp
++)
203 * Display version information to stdout and exit.
206 _zed_conf_display_version(void)
209 ZFS_META_NAME
, ZFS_META_VERSION
, ZFS_META_RELEASE
);
215 * Copy the [path] string to the [resultp] ptr.
216 * If [path] is not an absolute path, prefix it with the current working dir.
217 * If [resultp] is non-null, free its existing string before assignment.
220 _zed_conf_parse_path(char **resultp
, const char *path
)
224 assert(resultp
!= NULL
);
225 assert(path
!= NULL
);
230 if (path
[0] == '/') {
231 *resultp
= strdup(path
);
232 } else if (!getcwd(buf
, sizeof (buf
))) {
233 zed_log_die("Failed to get current working dir: %s",
235 } else if (strlcat(buf
, "/", sizeof (buf
)) >= sizeof (buf
)) {
236 zed_log_die("Failed to copy path: %s", strerror(ENAMETOOLONG
));
237 } else if (strlcat(buf
, path
, sizeof (buf
)) >= sizeof (buf
)) {
238 zed_log_die("Failed to copy path: %s", strerror(ENAMETOOLONG
));
240 *resultp
= strdup(buf
);
243 zed_log_die("Failed to copy path: %s", strerror(ENOMEM
));
247 * Parse the command-line options into the configuration [zcp].
250 zed_conf_parse_opts(struct zed_conf
*zcp
, int argc
, char **argv
)
252 const char * const opts
= ":hLVc:d:p:P:s:vfFMZ";
255 if (!zcp
|| !argv
|| !argv
[0])
256 zed_log_die("Failed to parse options: Internal error");
258 opterr
= 0; /* suppress default getopt err msgs */
260 while ((opt
= getopt(argc
, argv
, opts
)) != -1) {
263 _zed_conf_display_help(argv
[0], EXIT_SUCCESS
);
266 _zed_conf_display_license();
269 _zed_conf_display_version();
272 _zed_conf_parse_path(&zcp
->conf_file
, optarg
);
275 _zed_conf_parse_path(&zcp
->zedlet_dir
, optarg
);
278 _zed_conf_parse_path(&zcp
->pid_file
, optarg
);
281 _zed_conf_parse_path(&zcp
->path
, optarg
);
284 _zed_conf_parse_path(&zcp
->state_file
, optarg
);
293 zcp
->do_foreground
= 1;
304 _zed_conf_display_help(argv
[0], EXIT_SUCCESS
);
306 fprintf(stderr
, "%s: %s '-%c'\n\n", argv
[0],
307 "Invalid option", optopt
);
308 _zed_conf_display_help(argv
[0], EXIT_FAILURE
);
315 * Parse the configuration file into the configuration [zcp].
317 * FIXME: Not yet implemented.
320 zed_conf_parse_file(struct zed_conf
*zcp
)
323 zed_log_die("Failed to parse config: %s", strerror(EINVAL
));
327 * Scan the [zcp] zedlet_dir for files to exec based on the event class.
328 * Files must be executable by user, but not writable by group or other.
329 * Dotfiles are ignored.
331 * Return 0 on success with an updated set of zedlets,
332 * or -1 on error with errno set.
334 * FIXME: Check if zedlet_dir and all parent dirs are secure.
337 zed_conf_scan_dir(struct zed_conf
*zcp
)
339 zed_strings_t
*zedlets
;
341 struct dirent
*direntp
;
342 char pathname
[PATH_MAX
];
348 zed_log_msg(LOG_ERR
, "Failed to scan zedlet dir: %s",
352 zedlets
= zed_strings_create();
355 zed_log_msg(LOG_WARNING
, "Failed to scan dir \"%s\": %s",
356 zcp
->zedlet_dir
, strerror(errno
));
359 dirp
= opendir(zcp
->zedlet_dir
);
361 int errno_bak
= errno
;
362 zed_log_msg(LOG_WARNING
, "Failed to open dir \"%s\": %s",
363 zcp
->zedlet_dir
, strerror(errno
));
364 zed_strings_destroy(zedlets
);
368 while ((direntp
= readdir(dirp
))) {
369 if (direntp
->d_name
[0] == '.')
372 n
= snprintf(pathname
, sizeof (pathname
),
373 "%s/%s", zcp
->zedlet_dir
, direntp
->d_name
);
374 if ((n
< 0) || (n
>= sizeof (pathname
))) {
375 zed_log_msg(LOG_WARNING
, "Failed to stat \"%s\": %s",
376 direntp
->d_name
, strerror(ENAMETOOLONG
));
379 if (stat(pathname
, &st
) < 0) {
380 zed_log_msg(LOG_WARNING
, "Failed to stat \"%s\": %s",
381 pathname
, strerror(errno
));
384 if (!S_ISREG(st
.st_mode
)) {
385 zed_log_msg(LOG_INFO
,
386 "Ignoring \"%s\": not a regular file",
390 if ((st
.st_uid
!= 0) && !zcp
->do_force
) {
391 zed_log_msg(LOG_NOTICE
,
392 "Ignoring \"%s\": not owned by root",
396 if (!(st
.st_mode
& S_IXUSR
)) {
397 zed_log_msg(LOG_INFO
,
398 "Ignoring \"%s\": not executable by user",
402 if ((st
.st_mode
& S_IWGRP
) && !zcp
->do_force
) {
403 zed_log_msg(LOG_NOTICE
,
404 "Ignoring \"%s\": writable by group",
408 if ((st
.st_mode
& S_IWOTH
) && !zcp
->do_force
) {
409 zed_log_msg(LOG_NOTICE
,
410 "Ignoring \"%s\": writable by other",
414 if (zed_strings_add(zedlets
, NULL
, direntp
->d_name
) < 0) {
415 zed_log_msg(LOG_WARNING
,
416 "Failed to register \"%s\": %s",
417 direntp
->d_name
, strerror(errno
));
421 zed_log_msg(LOG_INFO
,
422 "Registered zedlet \"%s\"", direntp
->d_name
);
424 if (closedir(dirp
) < 0) {
425 int errno_bak
= errno
;
426 zed_log_msg(LOG_WARNING
, "Failed to close dir \"%s\": %s",
427 zcp
->zedlet_dir
, strerror(errno
));
428 zed_strings_destroy(zedlets
);
433 zed_strings_destroy(zcp
->zedlets
);
435 zcp
->zedlets
= zedlets
;
440 * Write the PID file specified in [zcp].
441 * Return 0 on success, -1 on error.
443 * This must be called after fork()ing to become a daemon (so the correct PID
444 * is recorded), but before daemonization is complete and the parent process
445 * exits (for synchronization with systemd).
448 zed_conf_write_pid(struct zed_conf
*zcp
)
450 const mode_t dirmode
= S_IRWXU
| S_IRGRP
| S_IXGRP
| S_IROTH
| S_IXOTH
;
451 const mode_t filemode
= S_IRUSR
| S_IWUSR
| S_IRGRP
| S_IROTH
;
458 if (!zcp
|| !zcp
->pid_file
) {
460 zed_log_msg(LOG_ERR
, "Failed to create PID file: %s",
464 assert(zcp
->pid_fd
== -1);
466 * Create PID file directory if needed.
468 n
= strlcpy(buf
, zcp
->pid_file
, sizeof (buf
));
469 if (n
>= sizeof (buf
)) {
470 errno
= ENAMETOOLONG
;
471 zed_log_msg(LOG_ERR
, "Failed to create PID file: %s",
475 p
= strrchr(buf
, '/');
479 if ((mkdirp(buf
, dirmode
) < 0) && (errno
!= EEXIST
)) {
480 zed_log_msg(LOG_ERR
, "Failed to create directory \"%s\": %s",
481 buf
, strerror(errno
));
485 * Obtain PID file lock.
489 zcp
->pid_fd
= open(zcp
->pid_file
, (O_RDWR
| O_CREAT
), filemode
);
491 if (zcp
->pid_fd
< 0) {
492 zed_log_msg(LOG_ERR
, "Failed to open PID file \"%s\": %s",
493 zcp
->pid_file
, strerror(errno
));
496 rv
= zed_file_lock(zcp
->pid_fd
);
498 zed_log_msg(LOG_ERR
, "Failed to lock PID file \"%s\": %s",
499 zcp
->pid_file
, strerror(errno
));
502 pid_t pid
= zed_file_is_locked(zcp
->pid_fd
);
505 "Failed to test lock on PID file \"%s\"",
507 } else if (pid
> 0) {
509 "Found PID %d bound to PID file \"%s\"",
513 "Inconsistent lock state on PID file \"%s\"",
521 n
= snprintf(buf
, sizeof (buf
), "%d\n", (int)getpid());
522 if ((n
< 0) || (n
>= sizeof (buf
))) {
524 zed_log_msg(LOG_ERR
, "Failed to write PID file \"%s\": %s",
525 zcp
->pid_file
, strerror(errno
));
526 } else if (zed_file_write_n(zcp
->pid_fd
, buf
, n
) != n
) {
527 zed_log_msg(LOG_ERR
, "Failed to write PID file \"%s\": %s",
528 zcp
->pid_file
, strerror(errno
));
529 } else if (fdatasync(zcp
->pid_fd
) < 0) {
530 zed_log_msg(LOG_ERR
, "Failed to sync PID file \"%s\": %s",
531 zcp
->pid_file
, strerror(errno
));
537 if (zcp
->pid_fd
>= 0) {
538 (void) close(zcp
->pid_fd
);
545 * Open and lock the [zcp] state_file.
546 * Return 0 on success, -1 on error.
548 * FIXME: Move state information into kernel.
551 zed_conf_open_state(struct zed_conf
*zcp
)
553 char dirbuf
[PATH_MAX
];
554 mode_t dirmode
= S_IRWXU
| S_IRGRP
| S_IXGRP
| S_IROTH
| S_IXOTH
;
559 if (!zcp
|| !zcp
->state_file
) {
561 zed_log_msg(LOG_ERR
, "Failed to open state file: %s",
565 n
= strlcpy(dirbuf
, zcp
->state_file
, sizeof (dirbuf
));
566 if (n
>= sizeof (dirbuf
)) {
567 errno
= ENAMETOOLONG
;
568 zed_log_msg(LOG_WARNING
, "Failed to open state file: %s",
572 p
= strrchr(dirbuf
, '/');
576 if ((mkdirp(dirbuf
, dirmode
) < 0) && (errno
!= EEXIST
)) {
577 zed_log_msg(LOG_WARNING
,
578 "Failed to create directory \"%s\": %s",
579 dirbuf
, strerror(errno
));
582 if (zcp
->state_fd
>= 0) {
583 if (close(zcp
->state_fd
) < 0) {
584 zed_log_msg(LOG_WARNING
,
585 "Failed to close state file \"%s\": %s",
586 zcp
->state_file
, strerror(errno
));
591 (void) unlink(zcp
->state_file
);
593 zcp
->state_fd
= open(zcp
->state_file
,
594 (O_RDWR
| O_CREAT
), (S_IRUSR
| S_IWUSR
| S_IRGRP
| S_IROTH
));
595 if (zcp
->state_fd
< 0) {
596 zed_log_msg(LOG_WARNING
, "Failed to open state file \"%s\": %s",
597 zcp
->state_file
, strerror(errno
));
600 rv
= zed_file_lock(zcp
->state_fd
);
602 zed_log_msg(LOG_WARNING
, "Failed to lock state file \"%s\": %s",
603 zcp
->state_file
, strerror(errno
));
607 pid_t pid
= zed_file_is_locked(zcp
->state_fd
);
609 zed_log_msg(LOG_WARNING
,
610 "Failed to test lock on state file \"%s\"",
612 } else if (pid
> 0) {
613 zed_log_msg(LOG_WARNING
,
614 "Found PID %d bound to state file \"%s\"",
615 pid
, zcp
->state_file
);
617 zed_log_msg(LOG_WARNING
,
618 "Inconsistent lock state on state file \"%s\"",
627 * Read the opened [zcp] state_file to obtain the eid & etime of the last event
628 * processed. Write the state from the last event to the [eidp] & [etime] args
629 * passed by reference. Note that etime[] is an array of size 2.
630 * Return 0 on success, -1 on error.
633 zed_conf_read_state(struct zed_conf
*zcp
, uint64_t *eidp
, int64_t etime
[])
639 if (!zcp
|| !eidp
|| !etime
) {
642 "Failed to read state file: %s", strerror(errno
));
645 if (lseek(zcp
->state_fd
, 0, SEEK_SET
) == (off_t
)-1) {
646 zed_log_msg(LOG_WARNING
,
647 "Failed to reposition state file offset: %s",
652 iov
[0].iov_base
= eidp
;
653 len
+= iov
[0].iov_len
= sizeof (*eidp
);
654 iov
[1].iov_base
= &etime
[0];
655 len
+= iov
[1].iov_len
= sizeof (etime
[0]);
656 iov
[2].iov_base
= &etime
[1];
657 len
+= iov
[2].iov_len
= sizeof (etime
[1]);
659 n
= readv(zcp
->state_fd
, iov
, 3);
663 zed_log_msg(LOG_WARNING
,
664 "Failed to read state file \"%s\": %s",
665 zcp
->state_file
, strerror(errno
));
667 } else if (n
!= len
) {
669 zed_log_msg(LOG_WARNING
,
670 "Failed to read state file \"%s\": Read %d of %d bytes",
671 zcp
->state_file
, n
, len
);
678 * Write the [eid] & [etime] of the last processed event to the opened
679 * [zcp] state_file. Note that etime[] is an array of size 2.
680 * Return 0 on success, -1 on error.
683 zed_conf_write_state(struct zed_conf
*zcp
, uint64_t eid
, int64_t etime
[])
692 "Failed to write state file: %s", strerror(errno
));
695 if (lseek(zcp
->state_fd
, 0, SEEK_SET
) == (off_t
)-1) {
696 zed_log_msg(LOG_WARNING
,
697 "Failed to reposition state file offset: %s",
702 iov
[0].iov_base
= &eid
;
703 len
+= iov
[0].iov_len
= sizeof (eid
);
704 iov
[1].iov_base
= &etime
[0];
705 len
+= iov
[1].iov_len
= sizeof (etime
[0]);
706 iov
[2].iov_base
= &etime
[1];
707 len
+= iov
[2].iov_len
= sizeof (etime
[1]);
709 n
= writev(zcp
->state_fd
, iov
, 3);
711 zed_log_msg(LOG_WARNING
,
712 "Failed to write state file \"%s\": %s",
713 zcp
->state_file
, strerror(errno
));
718 zed_log_msg(LOG_WARNING
,
719 "Failed to write state file \"%s\": Wrote %d of %d bytes",
720 zcp
->state_file
, n
, len
);
723 if (fdatasync(zcp
->state_fd
) < 0) {
724 zed_log_msg(LOG_WARNING
,
725 "Failed to sync state file \"%s\": %s",
726 zcp
->state_file
, strerror(errno
));