#include #include #include #include #include #include #include #include "prio.h" #include "debug.h" #include #include "structs.h" // // This prioritizer suits iSCSI needs, makes it possible to prefer one path. // // (It's a bit of a misnomer since supports the client side [eg. open-iscsi] // instead of just "iet".) // // Usage: // prio "iet" // prio_args "preferredip=10.11.12.13" // // Uses /dev/disk/by-path to find the IP of the device. // Assigns prio 20 (high) to the preferred IP and prio 10 (low) to the rest. // // by Olivier Lambert // #define dc_log(prio, msg) condlog(prio, "%s: iet prio: " msg, dev) // // name: find_regex // @param string: string you want to search into // @param regex: the pattern used // @return result: string finded in string with regex, "none" if none char *find_regex(char * string, char * regex) { int err; regex_t preg; err = regcomp(&preg, regex, REG_EXTENDED); if (err == 0) { int match; size_t nmatch = 0; regmatch_t *pmatch = NULL; nmatch = preg.re_nsub; pmatch = malloc(sizeof(*pmatch) * nmatch); if (pmatch) { match = regexec(&preg, string, nmatch, pmatch, 0); regfree(&preg); if (match == 0) { char *result = NULL; int start = pmatch[0].rm_so; int end = pmatch[0].rm_eo; size_t size = end - start; result = malloc (sizeof(*result) * (size + 1)); if (result) { strncpy(result, &string[start], size); result[size] = '\0'; free(pmatch); return result; } } free(pmatch); } } return NULL; } // // name: inet_prio // @param // @return prio int iet_prio(const char *dev, char * args) { char preferredip_buff[255] = ""; char *preferredip = &preferredip_buff[0]; // Phase 1 : checks. If anyone fails, return prio 0. // check if args exists if (!args) { dc_log(0, "need prio_args with preferredip set"); return 0; } // check if args format is OK if (sscanf(args, "preferredip=%s", preferredip) ==1) {} else { dc_log(0, "unexpected prio_args format"); return 0; } // check if ip is not too short if (strlen(preferredip) <= 7) { dc_log(0, "prio args: preferredip too short"); return 0; } // Phase 2 : find device in /dev/disk/by-path to match device/ip DIR *dir_p; struct dirent *dir_entry_p; enum { BUFFERSIZE = 1024 }; char buffer[BUFFERSIZE]; char fullpath[BUFFERSIZE] = "/dev/disk/by-path/"; dir_p = opendir(fullpath); // loop to find device in /dev/disk/by-path while( NULL != (dir_entry_p = readdir(dir_p))) { if (dir_entry_p->d_name[0] != '.') { char path[BUFFERSIZE] = "/dev/disk/by-path/"; strcat(path,dir_entry_p->d_name); ssize_t nchars = readlink(path, buffer, sizeof(buffer)-1); if (nchars != -1) { char *device; buffer[nchars] = '\0'; device = find_regex(buffer,"(sd[a-z]+)"); // if device parsed is the right one if (device!=NULL && strncmp(device, dev, strlen(device)) == 0) { char *ip; ip = find_regex(dir_entry_p->d_name,"([0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3})"); // if prefferedip and ip fetched matches if (ip!=NULL && strncmp(ip, preferredip, strlen(ip)) == 0) { // high prio free(ip); free(device); closedir(dir_p); return 20; } free(ip); } free(device); } else { printf("error\n"); } } } // nothing found, low prio closedir(dir_p); return 10; } int getprio(struct path * pp, char * args, __attribute__((unused)) unsigned int timeout) { return iet_prio(pp->dev, args); }