diff options
Diffstat (limited to 'libmultipath/prkey.c')
-rw-r--r-- | libmultipath/prkey.c | 166 |
1 files changed, 166 insertions, 0 deletions
diff --git a/libmultipath/prkey.c b/libmultipath/prkey.c new file mode 100644 index 0000000..89b90ed --- /dev/null +++ b/libmultipath/prkey.c @@ -0,0 +1,166 @@ +#include "structs.h" +#include "file.h" +#include "debug.h" +#include "config.h" +#include "util.h" +#include "propsel.h" +#include "prkey.h" +#include <sys/types.h> +#include <unistd.h> +#include <stdio.h> +#include <string.h> +#include <inttypes.h> +#include <errno.h> + +#define PRKEY_READ 0 +#define PRKEY_WRITE 1 + +static int do_prkey(int fd, char *wwid, char *keystr, int cmd) +{ + char buf[4097]; + char *ptr; + off_t start = 0; + int bytes; + + while (1) { + if (lseek(fd, start, SEEK_SET) < 0) { + condlog(0, "prkey file read lseek failed : %s", + strerror(errno)); + return 1; + } + bytes = read(fd, buf, 4096); + if (bytes < 0) { + if (errno == EINTR || errno == EAGAIN) + continue; + condlog(0, "failed to read from prkey file : %s", + strerror(errno)); + return 1; + } + if (!bytes) { + ptr = NULL; + break; + } + buf[bytes] = '\0'; + ptr = strstr(buf, wwid); + while (ptr) { + if (ptr == buf || *(ptr - 1) != ' ' || + *(ptr + strlen(wwid)) != '\n') + ptr = strstr(ptr + strlen(wwid), wwid); + else + break; + } + if (ptr) { + condlog(3, "found prkey for '%s'", wwid); + ptr[strlen(wwid)] = '\0'; + if (ptr - PRKEY_SIZE < buf || + (ptr - PRKEY_SIZE != buf && + *(ptr - PRKEY_SIZE - 1) != '\n')) { + condlog(0, "malformed prkey file line for wwid: '%s'", ptr); + return 1; + } + ptr = ptr - PRKEY_SIZE; + break; + } + ptr = strrchr(buf, '\n'); + if (ptr == NULL) { + condlog(4, "couldn't file newline, assuming end of file"); + break; + } + start = start + (ptr - buf) + 1; + } + if (cmd == PRKEY_READ) { + if (!ptr || *ptr == '#') + return 1; + memcpy(keystr, ptr, PRKEY_SIZE - 1); + keystr[PRKEY_SIZE - 1] = '\0'; + return 0; + } + if (!ptr && !keystr) + return 0; + if (ptr) { + if (lseek(fd, start + (ptr - buf), SEEK_SET) < 0) { + condlog(0, "prkey write lseek failed : %s", + strerror(errno)); + return 1; + } + } + if (!keystr) { + if (safe_write(fd, "#", 1) < 0) { + condlog(0, "failed to write to prkey file : %s", + strerror(errno)); + return 1; + } + return 0; + } + if (!ptr) { + if (lseek(fd, 0, SEEK_END) < 0) { + condlog(0, "prkey write lseek failed : %s", + strerror(errno)); + return 1; + } + } + bytes = sprintf(buf, "%s %s\n", keystr, wwid); + if (safe_write(fd, buf, bytes) < 0) { + condlog(0, "failed to write to prkey file: %s", + strerror(errno)); + return 1; + } + return 0; +} + +int get_prkey(struct config *conf, struct multipath *mpp, uint64_t *prkey) +{ + int fd; + int unused; + int ret = 1; + char keystr[PRKEY_SIZE]; + + if (!strlen(mpp->wwid)) + goto out; + + fd = open_file(conf->prkeys_file, &unused, PRKEYS_FILE_HEADER); + if (fd < 0) + goto out; + ret = do_prkey(fd, mpp->wwid, keystr, PRKEY_READ); + if (ret) + goto out_file; + ret = !!parse_prkey(keystr, prkey); +out_file: + close(fd); +out: + return ret; +} + +int set_prkey(struct config *conf, struct multipath *mpp, uint64_t prkey) +{ + int fd; + int can_write = 1; + int ret = 1; + char keystr[PRKEY_SIZE]; + + if (!strlen(mpp->wwid)) + goto out; + + fd = open_file(conf->prkeys_file, &can_write, PRKEYS_FILE_HEADER); + if (fd < 0) + goto out; + if (!can_write) { + condlog(0, "cannot set prkey, prkeys file is read-only"); + goto out_file; + } + if (prkey) { + snprintf(keystr, PRKEY_SIZE, "0x%016" PRIx64, prkey); + keystr[PRKEY_SIZE - 1] = '\0'; + ret = do_prkey(fd, mpp->wwid, keystr, PRKEY_WRITE); + } + else + ret = do_prkey(fd, mpp->wwid, NULL, PRKEY_WRITE); + if (ret == 0) + select_reservation_key(conf, mpp); + if (get_be64(mpp->reservation_key) != prkey) + ret = 1; +out_file: + close(fd); +out: + return ret; +} |