blob: 5b094b09f4eb9d7bb2ce1fc7731cf8f51abd1c3c [file] [log] [blame]
/*
* COPYRIGHT (c) 2006
* THE REGENTS OF THE UNIVERSITY OF MICHIGAN
* ALL RIGHTS RESERVED
*
* Permission is granted to use, copy, create derivative works
* and redistribute this software and such derivative works
* for any purpose, so long as the name of The University of
* Michigan is not used in any advertising or publicity
* pertaining to the use of distribution of this software
* without specific, written prior authorization. If the
* above copyright notice or any other identification of the
* University of Michigan is included in any copy of any
* portion of this software, then the disclaimer below must
* also be included.
*
* THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION
* FROM THE UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY
* PURPOSE, AND WITHOUT WARRANTY BY THE UNIVERSITY OF
* MICHIGAN OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING
* WITHOUT LIMITATION THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
* REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE LIABLE
* FOR ANY DAMAGES, INCLUDING SPECIAL, INDIRECT, INCIDENTAL, OR
* CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM ARISING
* OUT OF OR IN CONNECTION WITH THE USE OF THE SOFTWARE, EVEN
* IF IT HAS BEEN OR IS HEREAFTER ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGES.
*/
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include "fsloc.h"
#include "exportfs.h"
/* Debugging tool: prints out @servers info to syslog */
static void replicas_print(struct servers *sp)
{
int i;
if (!sp) {
xlog(L_NOTICE, "NULL replicas pointer\n");
return;
}
xlog(L_NOTICE, "replicas listsize=%i\n", sp->h_num);
for (i=0; i<sp->h_num; i++) {
xlog(L_NOTICE, " %s:%s\n",
sp->h_mp[i]->h_host, sp->h_mp[i]->h_path);
}
}
#ifdef DEBUG
/* Called by setting 'Method = stub' in config file. Just returns
* some syntactically correct gibberish for testing purposes.
*/
static struct servers *method_stub(char *key)
{
struct servers *sp;
struct mount_point *mp;
xlog(L_NOTICE, "called method_stub\n");
sp = malloc(sizeof(struct servers));
if (!sp)
return NULL;
mp = calloc(1, sizeof(struct mount_point));
if (!mp) {
free(sp);
return NULL;
}
sp->h_num = 1;
sp->h_mp[0] = mp;
mp->h_host = strdup("stub_server");
mp->h_path = strdup("/my/test/path");
sp->h_referral = 1;
return sp;
}
#endif /* DEBUG */
/* Scan @list, which is a NULL-terminated array of strings of the
* form path@host[+host], and return corresponding servers structure.
*/
static struct servers *parse_list(char **list)
{
int i;
struct servers *res;
struct mount_point *mp;
char *cp;
res = malloc(sizeof(struct servers));
if (!res)
return NULL;
res->h_num = 0;
/* parse each of the answers in sucession. */
for (i=0; list[i] && i<FSLOC_MAX_LIST; i++) {
mp = calloc(1, sizeof(struct mount_point));
if (!mp) {
release_replicas(res);
return NULL;
}
cp = strchr(list[i], '@');
if ((!cp) || list[i][0] != '/') {
xlog(L_WARNING, "invalid entry '%s'", list[i]);
continue; /* XXX Need better error handling */
}
res->h_mp[i] = mp;
res->h_num++;
mp->h_path = strndup(list[i], cp - list[i]);
cp++;
mp->h_host = strdup(cp);
/* hosts are '+' separated, kernel expects ':' separated */
while ( (cp = strchr(mp->h_host, '+')) )
*cp = ':';
}
return res;
}
/* @data is a string of form path@host[+host][:path@host[+host]]
*/
static struct servers *method_list(char *data)
{
char *copy, *ptr=data;
char **list;
int i, listsize;
struct servers *rv=NULL;
xlog(L_NOTICE, "method_list(%s)\n", data);
for (ptr--, listsize=1; ptr; ptr=index(ptr, ':'), listsize++)
ptr++;
list = malloc(listsize * sizeof(char *));
copy = strdup(data);
if (copy)
xlog(L_NOTICE, "converted to %s\n", copy);
if (list && copy) {
ptr = copy;
for (i=0; i<listsize; i++) {
list[i] = strsep(&ptr, ":");
}
rv = parse_list(list);
}
free(copy);
free(list);
replicas_print(rv);
return rv;
}
/* Returns appropriately filled struct servers, or NULL if had a problem */
struct servers *replicas_lookup(int method, char *data, char *key)
{
struct servers *sp=NULL;
switch(method) {
case FSLOC_NONE:
break;
case FSLOC_REFER:
sp = method_list(data);
if (sp)
sp->h_referral = 1;
break;
case FSLOC_REPLICA:
sp = method_list(data);
if (sp)
sp->h_referral = 0;
break;
#ifdef DEBUG
case FSLOC_STUB:
sp = method_stub(data);
break;
#endif
default:
xlog(L_WARNING, "Unknown method = %i", method);
}
replicas_print(sp);
return sp;
}
void release_replicas(struct servers *server)
{
int i;
if (!server) return;
for (i = 0; i < server->h_num; i++) {
free(server->h_mp[i]->h_host);
free(server->h_mp[i]->h_path);
free(server->h_mp[i]);
}
free(server);
}