/* * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved. * * This file is part of the device-mapper userspace tools. * * This copyrighted material is made available to anyone wishing to use, * modify, copy, or redistribute it subject to the terms and conditions * of the GNU Lesser General Public License v.2.1. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "dmlib.h" #include <sys/file.h> #include <fcntl.h> #include <dirent.h> static int _is_dir(const char *path) { struct stat st; if (stat(path, &st) < 0) { log_sys_error("stat", path); return 0; } if (!S_ISDIR(st.st_mode)) { log_error("Existing path %s is not " "a directory.", path); return 0; } return 1; } static int _create_dir_recursive(const char *dir) { char *orig, *s; int rc, r = 0; log_verbose("Creating directory \"%s\"", dir); /* Create parent directories */ orig = s = dm_strdup(dir); if (!s) { log_error("Failed to duplicate directory name."); return 0; } while ((s = strchr(s, '/')) != NULL) { *s = '\0'; if (*orig) { rc = mkdir(orig, 0777); if (rc < 0) { if (errno == EEXIST) { if (!_is_dir(orig)) goto_out; } else { if (errno != EROFS) log_sys_error("mkdir", orig); goto out; } } } *s++ = '/'; } /* Create final directory */ rc = mkdir(dir, 0777); if (rc < 0) { if (errno == EEXIST) { if (!_is_dir(dir)) goto_out; } else { if (errno != EROFS) log_sys_error("mkdir", orig); goto out; } } r = 1; out: dm_free(orig); return r; } int dm_create_dir(const char *dir) { struct stat info; if (!*dir) return 1; if (stat(dir, &info) == 0 && S_ISDIR(info.st_mode)) return 1; if (!_create_dir_recursive(dir)) return_0; return 1; } int dm_is_empty_dir(const char *dir) { struct dirent *dirent; DIR *d; if (!(d = opendir(dir))) { log_sys_error("opendir", dir); return 0; } while ((dirent = readdir(d))) if (strcmp(dirent->d_name, ".") && strcmp(dirent->d_name, "..")) break; if (closedir(d)) log_sys_error("closedir", dir); return dirent ? 0 : 1; } int dm_fclose(FILE *stream) { int prev_fail = ferror(stream); int fclose_fail = fclose(stream); /* If there was a previous failure, but fclose succeeded, clear errno, since ferror does not set it, and its value may be unrelated to the ferror-reported failure. */ if (prev_fail && !fclose_fail) errno = 0; return prev_fail || fclose_fail ? EOF : 0; } int dm_create_lockfile(const char *lockfile) { int fd, value; size_t bufferlen; ssize_t write_out; struct flock lock; char buffer[50]; int retries = 0; if ((fd = open(lockfile, O_CREAT | O_WRONLY, (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH))) < 0) { log_error("Cannot open lockfile [%s], error was [%s]", lockfile, strerror(errno)); return 0; } lock.l_type = F_WRLCK; lock.l_start = 0; lock.l_whence = SEEK_SET; lock.l_len = 0; retry_fcntl: if (fcntl(fd, F_SETLK, &lock) < 0) { switch (errno) { case EINTR: goto retry_fcntl; case EACCES: case EAGAIN: if (retries == 20) { log_error("Cannot lock lockfile [%s], error was [%s]", lockfile, strerror(errno)); break; } else { ++ retries; usleep(1000); goto retry_fcntl; } default: log_error("process is already running"); } goto fail_close; } if (ftruncate(fd, 0) < 0) { log_error("Cannot truncate pidfile [%s], error was [%s]", lockfile, strerror(errno)); goto fail_close_unlink; } memset(buffer, 0, sizeof(buffer)); snprintf(buffer, sizeof(buffer)-1, "%u\n", getpid()); bufferlen = strlen(buffer); write_out = write(fd, buffer, bufferlen); if ((write_out < 0) || (write_out == 0 && errno)) { log_error("Cannot write pid to pidfile [%s], error was [%s]", lockfile, strerror(errno)); goto fail_close_unlink; } if ((write_out == 0) || ((size_t)write_out < bufferlen)) { log_error("Cannot write pid to pidfile [%s], shortwrite of" "[%" PRIsize_t "] bytes, expected [%" PRIsize_t "]\n", lockfile, write_out, bufferlen); goto fail_close_unlink; } if ((value = fcntl(fd, F_GETFD, 0)) < 0) { log_error("Cannot get close-on-exec flag from pidfile [%s], " "error was [%s]", lockfile, strerror(errno)); goto fail_close_unlink; } value |= FD_CLOEXEC; if (fcntl(fd, F_SETFD, value) < 0) { log_error("Cannot set close-on-exec flag from pidfile [%s], " "error was [%s]", lockfile, strerror(errno)); goto fail_close_unlink; } return 1; fail_close_unlink: if (unlink(lockfile)) log_sys_debug("unlink", lockfile); fail_close: if (close(fd)) log_sys_debug("close", lockfile); return 0; } int dm_daemon_is_running(const char* lockfile) { int fd; struct flock lock; if((fd = open(lockfile, O_RDONLY)) < 0) return 0; lock.l_type = F_WRLCK; lock.l_start = 0; lock.l_whence = SEEK_SET; lock.l_len = 0; if (fcntl(fd, F_GETLK, &lock) < 0) { log_error("Cannot check lock status of lockfile [%s], error was [%s]", lockfile, strerror(errno)); if (close(fd)) stack; return 0; } if (close(fd)) stack; return (lock.l_type == F_UNLCK) ? 0 : 1; }