]> granicus.if.org Git - zfs/blobdiff - cmd/zed/zed_conf.c
Fix shellcheck v0.4.6 warnings
[zfs] / cmd / zed / zed_conf.c
index 5e21a3db9bc20b8540e85a39b8a19257e34f17d9..5b27f1e4f1f248531f7af9b5113577da6fc38e9e 100644 (file)
@@ -1,27 +1,15 @@
 /*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License (the "License").
- * You may not use this file except in compliance with the License.
- *
- * You can obtain a copy of the license from the top-level
- * OPENSOLARIS.LICENSE or <http://opensource.org/licenses/CDDL-1.0>.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each file
- * and include the License file from the top-level OPENSOLARIS.LICENSE.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information: Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- */
-
-/*
+ * This file is part of the ZFS Event Daemon (ZED)
+ * for ZFS on Linux (ZoL) <http://zfsonlinux.org/>.
  * Developed at Lawrence Livermore National Laboratory (LLNL-CODE-403049).
  * Copyright (C) 2013-2014 Lawrence Livermore National Security, LLC.
+ * Refer to the ZoL git commit log for authoritative copyright attribution.
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License Version 1.0 (CDDL-1.0).
+ * You can obtain a copy of the license from the top-level file
+ * "OPENSOLARIS.LICENSE" or at <http://opensource.org/licenses/CDDL-1.0>.
+ * You may not use this file except in compliance with the license.
  */
 
 #include <assert.h>
@@ -58,6 +46,7 @@ zed_conf_create(void)
        zcp->syslog_facility = LOG_DAEMON;
        zcp->min_events = ZED_MIN_EVENTS;
        zcp->max_events = ZED_MAX_EVENTS;
+       zcp->pid_fd = -1;
        zcp->zedlets = NULL;            /* created via zed_conf_scan_dir() */
        zcp->state_fd = -1;             /* opened via zed_conf_open_state() */
        zcp->zfs_hdl = NULL;            /* opened via zed_event_init() */
@@ -98,6 +87,7 @@ zed_conf_destroy(struct zed_conf *zcp)
                        zed_log_msg(LOG_WARNING,
                            "Failed to close state file \"%s\": %s",
                            zcp->state_file, strerror(errno));
+               zcp->state_fd = -1;
        }
        if (zcp->pid_file) {
                if ((unlink(zcp->pid_file) < 0) && (errno != ENOENT))
@@ -105,21 +95,33 @@ zed_conf_destroy(struct zed_conf *zcp)
                            "Failed to remove PID file \"%s\": %s",
                            zcp->pid_file, strerror(errno));
        }
-       if (zcp->conf_file)
+       if (zcp->pid_fd >= 0) {
+               if (close(zcp->pid_fd) < 0)
+                       zed_log_msg(LOG_WARNING,
+                           "Failed to close PID file \"%s\": %s",
+                           zcp->pid_file, strerror(errno));
+               zcp->pid_fd = -1;
+       }
+       if (zcp->conf_file) {
                free(zcp->conf_file);
-
-       if (zcp->pid_file)
+               zcp->conf_file = NULL;
+       }
+       if (zcp->pid_file) {
                free(zcp->pid_file);
-
-       if (zcp->zedlet_dir)
+               zcp->pid_file = NULL;
+       }
+       if (zcp->zedlet_dir) {
                free(zcp->zedlet_dir);
-
-       if (zcp->state_file)
+               zcp->zedlet_dir = NULL;
+       }
+       if (zcp->state_file) {
                free(zcp->state_file);
-
-       if (zcp->zedlets)
+               zcp->state_file = NULL;
+       }
+       if (zcp->zedlets) {
                zed_strings_destroy(zcp->zedlets);
-
+               zcp->zedlets = NULL;
+       }
        free(zcp);
 }
 
@@ -182,10 +184,9 @@ _zed_conf_display_license(void)
            "The ZFS Event Daemon (ZED) is distributed under the terms of the",
            "  Common Development and Distribution License (CDDL-1.0)",
            "  <http://opensource.org/licenses/CDDL-1.0>.",
+           "",
            "Developed at Lawrence Livermore National Laboratory"
            " (LLNL-CODE-403049).",
-           "Copyright (C) 2013-2014"
-           " Lawrence Livermore National Security, LLC.",
            "",
            NULL
        };
@@ -393,19 +394,19 @@ zed_conf_scan_dir(struct zed_conf *zcp)
                            direntp->d_name);
                        continue;
                }
-               if ((st.st_mode & S_IWGRP) & !zcp->do_force) {
+               if ((st.st_mode & S_IWGRP) && !zcp->do_force) {
                        zed_log_msg(LOG_NOTICE,
                            "Ignoring \"%s\": writable by group",
                            direntp->d_name);
                        continue;
                }
-               if ((st.st_mode & S_IWOTH) & !zcp->do_force) {
+               if ((st.st_mode & S_IWOTH) && !zcp->do_force) {
                        zed_log_msg(LOG_NOTICE,
                            "Ignoring \"%s\": writable by other",
                            direntp->d_name);
                        continue;
                }
-               if (zed_strings_add(zedlets, direntp->d_name) < 0) {
+               if (zed_strings_add(zedlets, NULL, direntp->d_name) < 0) {
                        zed_log_msg(LOG_WARNING,
                            "Failed to register \"%s\": %s",
                            direntp->d_name, strerror(errno));
@@ -437,65 +438,101 @@ zed_conf_scan_dir(struct zed_conf *zcp)
  * This must be called after fork()ing to become a daemon (so the correct PID
  * is recorded), but before daemonization is complete and the parent process
  * exits (for synchronization with systemd).
- *
- * FIXME: Only update the PID file after verifying the PID previously stored
- * in the PID file no longer exists or belongs to a foreign process
- * in order to ensure the daemon cannot be started more than once.
- * (This check is currently done by zed_conf_open_state().)
  */
 int
 zed_conf_write_pid(struct zed_conf *zcp)
 {
-       char dirbuf[PATH_MAX];
-       mode_t dirmode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
+       const mode_t dirmode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
+       const mode_t filemode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
+       char buf[PATH_MAX];
        int n;
        char *p;
        mode_t mask;
-       FILE *fp;
+       int rv;
 
        if (!zcp || !zcp->pid_file) {
                errno = EINVAL;
-               zed_log_msg(LOG_ERR, "Failed to write PID file: %s",
+               zed_log_msg(LOG_ERR, "Failed to create PID file: %s",
                    strerror(errno));
                return (-1);
        }
-       n = strlcpy(dirbuf, zcp->pid_file, sizeof (dirbuf));
-       if (n >= sizeof (dirbuf)) {
+       assert(zcp->pid_fd == -1);
+       /*
+        * Create PID file directory if needed.
+        */
+       n = strlcpy(buf, zcp->pid_file, sizeof (buf));
+       if (n >= sizeof (buf)) {
                errno = ENAMETOOLONG;
-               zed_log_msg(LOG_WARNING, "Failed to write PID file: %s",
+               zed_log_msg(LOG_ERR, "Failed to create PID file: %s",
                    strerror(errno));
-               return (-1);
+               goto err;
        }
-       p = strrchr(dirbuf, '/');
+       p = strrchr(buf, '/');
        if (p)
                *p = '\0';
 
-       if ((mkdirp(dirbuf, dirmode) < 0) && (errno != EEXIST)) {
-               zed_log_msg(LOG_WARNING,
-                   "Failed to create directory \"%s\": %s",
-                   dirbuf, strerror(errno));
-               return (-1);
+       if ((mkdirp(buf, dirmode) < 0) && (errno != EEXIST)) {
+               zed_log_msg(LOG_ERR, "Failed to create directory \"%s\": %s",
+                   buf, strerror(errno));
+               goto err;
        }
-       (void) unlink(zcp->pid_file);
-
+       /*
+        * Obtain PID file lock.
+        */
        mask = umask(0);
        umask(mask | 022);
-       fp = fopen(zcp->pid_file, "w");
+       zcp->pid_fd = open(zcp->pid_file, (O_RDWR | O_CREAT), filemode);
        umask(mask);
-
-       if (!fp) {
-               zed_log_msg(LOG_WARNING, "Failed to open PID file \"%s\": %s",
+       if (zcp->pid_fd < 0) {
+               zed_log_msg(LOG_ERR, "Failed to open PID file \"%s\": %s",
                    zcp->pid_file, strerror(errno));
-       } else if (fprintf(fp, "%d\n", (int) getpid()) == EOF) {
-               zed_log_msg(LOG_WARNING, "Failed to write PID file \"%s\": %s",
+               goto err;
+       }
+       rv = zed_file_lock(zcp->pid_fd);
+       if (rv < 0) {
+               zed_log_msg(LOG_ERR, "Failed to lock PID file \"%s\": %s",
                    zcp->pid_file, strerror(errno));
-       } else if (fclose(fp) == EOF) {
-               zed_log_msg(LOG_WARNING, "Failed to close PID file \"%s\": %s",
+               goto err;
+       } else if (rv > 0) {
+               pid_t pid = zed_file_is_locked(zcp->pid_fd);
+               if (pid < 0) {
+                       zed_log_msg(LOG_ERR,
+                           "Failed to test lock on PID file \"%s\"",
+                           zcp->pid_file);
+               } else if (pid > 0) {
+                       zed_log_msg(LOG_ERR,
+                           "Found PID %d bound to PID file \"%s\"",
+                           pid, zcp->pid_file);
+               } else {
+                       zed_log_msg(LOG_ERR,
+                           "Inconsistent lock state on PID file \"%s\"",
+                           zcp->pid_file);
+               }
+               goto err;
+       }
+       /*
+        * Write PID file.
+        */
+       n = snprintf(buf, sizeof (buf), "%d\n", (int)getpid());
+       if ((n < 0) || (n >= sizeof (buf))) {
+               errno = ERANGE;
+               zed_log_msg(LOG_ERR, "Failed to write PID file \"%s\": %s",
+                   zcp->pid_file, strerror(errno));
+       } else if (zed_file_write_n(zcp->pid_fd, buf, n) != n) {
+               zed_log_msg(LOG_ERR, "Failed to write PID file \"%s\": %s",
+                   zcp->pid_file, strerror(errno));
+       } else if (fdatasync(zcp->pid_fd) < 0) {
+               zed_log_msg(LOG_ERR, "Failed to sync PID file \"%s\": %s",
                    zcp->pid_file, strerror(errno));
        } else {
                return (0);
        }
-       (void) unlink(zcp->pid_file);
+
+err:
+       if (zcp->pid_fd >= 0) {
+               (void) close(zcp->pid_fd);
+               zcp->pid_fd = -1;
+       }
        return (-1);
 }
 
@@ -503,8 +540,7 @@ zed_conf_write_pid(struct zed_conf *zcp)
  * Open and lock the [zcp] state_file.
  * Return 0 on success, -1 on error.
  *
- * FIXME: If state_file exists, verify ownership & permissions.
- * FIXME: Move lock to pid_file instead.
+ * FIXME: Move state information into kernel.
  */
 int
 zed_conf_open_state(struct zed_conf *zcp)
@@ -601,7 +637,7 @@ zed_conf_read_state(struct zed_conf *zcp, uint64_t *eidp, int64_t etime[])
                    "Failed to read state file: %s", strerror(errno));
                return (-1);
        }
-       if (lseek(zcp->state_fd, 0, SEEK_SET) == (off_t) -1) {
+       if (lseek(zcp->state_fd, 0, SEEK_SET) == (off_t)-1) {
                zed_log_msg(LOG_WARNING,
                    "Failed to reposition state file offset: %s",
                    strerror(errno));
@@ -651,7 +687,7 @@ zed_conf_write_state(struct zed_conf *zcp, uint64_t eid, int64_t etime[])
                    "Failed to write state file: %s", strerror(errno));
                return (-1);
        }
-       if (lseek(zcp->state_fd, 0, SEEK_SET) == (off_t) -1) {
+       if (lseek(zcp->state_fd, 0, SEEK_SET) == (off_t)-1) {
                zed_log_msg(LOG_WARNING,
                    "Failed to reposition state file offset: %s",
                    strerror(errno));