/* * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "dmlib.h" #include #include #include 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 && errno != EEXIST) { if (errno != EROFS) log_sys_error("mkdir", orig); goto out; } } *s++ = '/'; } /* Create final directory */ rc = mkdir(dir, 0777); if (rc < 0 && errno != EEXIST) { 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) return _create_dir_recursive(dir); if (S_ISDIR(info.st_mode)) return 1; log_error("Directory \"%s\" not found", dir); return 0; } 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; break; 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)) stack; fail_close: if (close(fd)) stack; 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; }