blob: 2313b6f8fa64049c63469fd9f0e9b340b6909c91 [file] [log] [blame]
/*
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