/*
*
* (C) Copyright 2008 Hewlett-Packard Development Company, L.P
*
* This file is released under the GPL
*/
/*
* Prioritizer for device mapper multipath, where specific paths and the
* corresponding priority values are provided as arguments.
*
* This prioritizer assigns the priority value provided in the configuration
* file based on the comparison made between the specified paths and the path
* instance for which this is called.
* Paths can be specified as a regular expression of devname of the path or
* as hbtl information of the path.
*
* Examples:
* prio "weightedpath hbtl 1:.:.:. 2 4:.:.:. 4"
* prio "weightedpath devname sda 10 sde 20"
*
* Returns zero as the default priority.
*/
#include <stdio.h>
#include <string.h>
#include "prio.h"
#include "weightedpath.h"
#include "config.h"
#include "structs.h"
#include "memory.h"
#include "debug.h"
#include <regex.h>
#include "structs_vec.h"
#include "print.h"
#include "util.h"
#define CHECK_LEN \
do { \
if ((p - str) >= (len - 1)) { \
condlog(0, "%s: %s - buffer size too small", pp->dev, pp->prio.name); \
return -1; \
} \
} while(0)
static int
build_serial_path(struct path *pp, char *str, int len)
{
char *p = str;
p += snprint_path_serial(p, str + len - p, pp);
CHECK_LEN;
return 0;
}
static int
build_wwn_path(struct path *pp, char *str, int len)
{
char *p = str;
p += snprint_host_wwnn(p, str + len - p, pp);
CHECK_LEN;
p += snprintf(p, str + len - p, ":");
CHECK_LEN;
p += snprint_host_wwpn(p, str + len - p, pp);
CHECK_LEN;
p += snprintf(p, str + len - p, ":");
CHECK_LEN;
p += snprint_tgt_wwnn(p, str + len - p, pp);
CHECK_LEN;
p += snprintf(p, str + len - p, ":");
CHECK_LEN;
p += snprint_tgt_wwpn(p, str + len - p, pp);
CHECK_LEN;
return 0;
}
/* main priority routine */
int prio_path_weight(struct path *pp, char *prio_args)
{
char path[FILE_NAME_SIZE];
char *arg;
char *temp, *regex, *prio;
char split_char[] = " \t";
int priority = DEFAULT_PRIORITY, path_found = 0;
regex_t pathe;
/* Return default priority if there is no argument */
if (!prio_args)
return priority;
arg = temp = STRDUP(prio_args);
regex = get_next_string(&temp, split_char);
/* Return default priority if the argument is not parseable */
if (!regex) {
FREE(arg);
return priority;
}
if (!strcmp(regex, HBTL)) {
sprintf(path, "%d:%d:%d:%d", pp->sg_id.host_no,
pp->sg_id.channel, pp->sg_id.scsi_id, pp->sg_id.lun);
} else if (!strcmp(regex, DEV_NAME)) {
strcpy(path, pp->dev);
} else if (!strcmp(regex, SERIAL)) {
if (build_serial_path(pp, path, FILE_NAME_SIZE) != 0) {
FREE(arg);
return priority;
}
} else if (!strcmp(regex, WWN)) {
if (build_wwn_path(pp, path, FILE_NAME_SIZE) != 0) {
FREE(arg);
return priority;
}
} else {
condlog(0, "%s: %s - Invalid arguments", pp->dev,
pp->prio.name);
FREE(arg);
return priority;
}
while (!path_found) {
if (!temp)
break;
if (!(regex = get_next_string(&temp, split_char)))
break;
if (!(prio = get_next_string(&temp, split_char)))
break;
if (!regcomp(&pathe, regex, REG_EXTENDED|REG_NOSUB)) {
if (!regexec(&pathe, path, 0, NULL, 0)) {
path_found = 1;
priority = atoi(prio);
}
regfree(&pathe);
}
}
FREE(arg);
return priority;
}
int getprio(struct path *pp, char *args,
__attribute__((unused)) unsigned int timeout)
{
return prio_path_weight(pp, args);
}