| /* |
| drbdadm_registry.c |
| |
| This file is part of DRBD by Philipp Reisner and Lars Ellenberg. |
| It was written by Johannes Thoma <johannes.thoma@linbit.com> |
| |
| Copyright (C) 2002-2008, LINBIT Information Technologies GmbH. |
| Copyright (C) 2002-2008, Philipp Reisner <philipp.reisner@linbit.com>. |
| Copyright (C) 2002-2008, Lars Ellenberg <lars.ellenberg@linbit.com>. |
| |
| drbd is free software; you can redistribute it and/or modify |
| it under the terms of the GNU General Public License as published by |
| the Free Software Foundation; either version 2, or (at your option) |
| any later version. |
| |
| drbd is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with drbd; see the file COPYING. If not, write to |
| the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. |
| |
| */ |
| |
| /* This keeps track of which DRBD minor was configured in which |
| * config file. This is required to have alternative config files |
| * (-c switch) and userland event handlers. |
| */ |
| |
| |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <ctype.h> |
| #include <string.h> |
| #include <errno.h> |
| #include <unistd.h> |
| #include <sys/types.h> |
| #include <sys/stat.h> |
| #include <string.h> |
| #include <limits.h> |
| |
| #include "config.h" |
| #include "registry.h" |
| |
| static void linkname_from_minor(char *linkname, int minor) |
| { |
| sprintf(linkname, "%s/drbd-minor-%d.conf", DRBD_RUN_DIR, minor); |
| } |
| |
| int unregister_minor(int minor) |
| { |
| char linkname[PATH_MAX]; |
| |
| linkname_from_minor(linkname, minor); |
| if (unlink(linkname) < 0) { |
| if (errno != ENOENT) { |
| perror("unlink"); |
| return -1; |
| } |
| } |
| return 0; |
| } |
| |
| static ssize_t __readlink(const char *path, char *buf, size_t bufsiz) |
| { |
| ssize_t ret; |
| |
| ret = readlink(path, buf, bufsiz); |
| if (ret >= 0) { |
| if (ret >= bufsiz) { |
| errno = ENAMETOOLONG; |
| return -1; |
| } |
| buf[ret] = 0; |
| } |
| return ret; |
| } |
| |
| static int register_path(const char *linkname, const char *path) |
| { |
| char target[PATH_MAX]; |
| |
| if (path[0] != '/') { |
| fprintf(stderr, "File %s: absolute path expected; won't " |
| "register relative path.", |
| path); |
| return -1; |
| } |
| /* safeguard against symlink loops in DRBD_RUN_DIR */ |
| if (!strncmp(path, DRBD_RUN_DIR "/", strlen(DRBD_RUN_DIR "/"))) |
| return -1; |
| if (__readlink(linkname, target, sizeof(target)) >= 0 && |
| !strcmp(target, path)) |
| return 0; |
| if (unlink(linkname) != 0 && errno != ENOENT) { |
| perror(linkname); |
| return -1; |
| } |
| if (mkdir(DRBD_RUN_DIR, S_IRWXU) != 0 && errno != EEXIST) { |
| perror(DRBD_RUN_DIR); |
| return -1; |
| } |
| if (symlink(path, linkname) != 0) { |
| fprintf(stderr, "symlink(%s, %s): %m\n", path, linkname); |
| return -1; |
| } |
| return 0; |
| } |
| |
| int register_minor(int minor, const char *path) |
| { |
| char linkname[PATH_MAX]; |
| |
| linkname_from_minor(linkname, minor); |
| return register_path(linkname, path); |
| } |
| |
| static char *resolve_symlink(const char *linkname) |
| { |
| static char target[PATH_MAX]; |
| |
| if (__readlink(linkname, target, sizeof(target)) < 0) |
| return NULL; |
| return target; |
| } |
| |
| char *lookup_minor(int minor) |
| { |
| static char linkname[PATH_MAX]; |
| struct stat stat_buf; |
| |
| linkname_from_minor(linkname, minor); |
| if (stat(linkname, &stat_buf) != 0) { |
| if (errno != ENOENT) |
| perror(linkname); |
| return NULL; |
| } |
| return resolve_symlink(linkname); |
| } |
| |
| static void linkname_from_resource_name(char *linkname, const char *name) |
| { |
| sprintf(linkname, "%s/drbd-resource-%s.conf", DRBD_RUN_DIR, name); |
| } |
| |
| int unregister_resource(const char *name) |
| { |
| char linkname[PATH_MAX]; |
| |
| linkname_from_resource_name(linkname, name); |
| if (unlink(linkname) != 0) { |
| if (errno != ENOENT) { |
| perror(linkname); |
| return -1; |
| } |
| } |
| return 0; |
| } |
| |
| int register_resource(const char *name, const char *path) |
| { |
| char linkname[PATH_MAX]; |
| |
| linkname_from_resource_name(linkname, name); |
| return register_path(linkname, path); |
| } |
| |
| /* This returns a static buffer containing the real |
| * configuration file known to be used last for this minor. |
| * If you need the return value longer, stuff it away with strdup. */ |
| char *lookup_resource(const char *name) |
| { |
| static char linkname[PATH_MAX]; |
| struct stat stat_buf; |
| |
| linkname_from_resource_name(linkname, name); |
| if (stat(linkname, &stat_buf) != 0) { |
| if (errno != ENOENT) |
| perror(linkname); |
| return NULL; |
| } |
| return resolve_symlink(linkname); |
| } |
| |
| |
| #ifdef TEST |
| |
| int main(int argc, char ** argv) |
| { |
| register_minor(1, "/etc/drbd-xy.conf"); |
| register_minor(15, "/etc/drbd-82.conf"); |
| register_minor(14, "/../../../../../../etc/drbd-82.conf"); |
| printf("Minor 1 is %s.\n", lookup_minor(1)); |
| printf("Minor 2 is %s.\n", lookup_minor(2)); |
| printf("Minor 14 is %s.\n", lookup_minor(14)); |
| printf("Minor 15 is %s.\n", lookup_minor(15)); |
| return 0; |
| } |
| |
| #endif |