89b90ed27639163e89b5dcbfd4717bc3622afa47
[multipath-tools/.git] / libmultipath / prkey.c
1 #include "structs.h"
2 #include "file.h"
3 #include "debug.h"
4 #include "config.h"
5 #include "util.h"
6 #include "propsel.h"
7 #include "prkey.h"
8 #include <sys/types.h>
9 #include <unistd.h>
10 #include <stdio.h>
11 #include <string.h>
12 #include <inttypes.h>
13 #include <errno.h>
14
15 #define PRKEY_READ 0
16 #define PRKEY_WRITE 1
17
18 static int do_prkey(int fd, char *wwid, char *keystr, int cmd)
19 {
20         char buf[4097];
21         char *ptr;
22         off_t start = 0;
23         int bytes;
24
25         while (1) {
26                 if (lseek(fd, start, SEEK_SET) < 0) {
27                         condlog(0, "prkey file read lseek failed : %s",
28                                 strerror(errno));
29                         return 1;
30                 }
31                 bytes = read(fd, buf, 4096);
32                 if (bytes < 0) {
33                         if (errno == EINTR || errno == EAGAIN)
34                                 continue;
35                         condlog(0, "failed to read from prkey file : %s",
36                                 strerror(errno));
37                         return 1;
38                 }
39                 if (!bytes) {
40                         ptr = NULL;
41                         break;
42                 }
43                 buf[bytes] = '\0';
44                 ptr = strstr(buf, wwid);
45                 while (ptr) {
46                         if (ptr == buf || *(ptr - 1) != ' ' ||
47                             *(ptr + strlen(wwid)) != '\n')
48                                 ptr = strstr(ptr + strlen(wwid), wwid);
49                         else
50                                 break;
51                 }
52                 if (ptr) {
53                         condlog(3, "found prkey for '%s'", wwid);
54                         ptr[strlen(wwid)] = '\0';
55                         if (ptr - PRKEY_SIZE < buf ||
56                             (ptr - PRKEY_SIZE != buf &&
57                              *(ptr - PRKEY_SIZE - 1) != '\n')) {
58                                 condlog(0, "malformed prkey file line for wwid: '%s'", ptr);
59                                 return 1;
60                         }
61                         ptr = ptr - PRKEY_SIZE;
62                         break;
63                 }
64                 ptr = strrchr(buf, '\n');
65                 if (ptr == NULL) {
66                         condlog(4, "couldn't file newline, assuming end of file");
67                         break;
68                 }
69                 start = start + (ptr - buf) + 1;
70         }
71         if (cmd == PRKEY_READ) {
72                 if (!ptr || *ptr == '#')
73                         return 1;
74                 memcpy(keystr, ptr, PRKEY_SIZE - 1);
75                 keystr[PRKEY_SIZE - 1] = '\0';
76                 return 0;
77         }
78         if (!ptr && !keystr)
79                 return 0;
80         if (ptr) {
81                 if (lseek(fd, start + (ptr - buf), SEEK_SET) < 0) {
82                         condlog(0, "prkey write lseek failed : %s",
83                                 strerror(errno));
84                         return 1;
85                 }
86         }
87         if (!keystr) {
88                 if (safe_write(fd, "#", 1) < 0) {
89                         condlog(0, "failed to write to prkey file : %s",
90                                 strerror(errno));
91                         return 1;
92                 }
93                 return 0;
94         }
95         if (!ptr) {
96                 if (lseek(fd, 0, SEEK_END) < 0) {
97                         condlog(0, "prkey write lseek failed : %s",
98                                 strerror(errno));
99                         return 1;
100                 }
101         }
102         bytes = sprintf(buf, "%s %s\n", keystr, wwid);
103         if (safe_write(fd, buf, bytes) < 0) {
104                 condlog(0, "failed to write to prkey file: %s",
105                         strerror(errno));
106                 return 1;
107         }
108         return 0;
109 }
110
111 int get_prkey(struct config *conf, struct multipath *mpp, uint64_t *prkey)
112 {
113         int fd;
114         int unused;
115         int ret = 1;
116         char keystr[PRKEY_SIZE];
117
118         if (!strlen(mpp->wwid))
119                 goto out;
120
121         fd = open_file(conf->prkeys_file, &unused, PRKEYS_FILE_HEADER);
122         if (fd < 0)
123                 goto out;
124         ret = do_prkey(fd, mpp->wwid, keystr, PRKEY_READ);
125         if (ret)
126                 goto out_file;
127         ret = !!parse_prkey(keystr, prkey);
128 out_file:
129         close(fd);
130 out:
131         return ret;
132 }
133
134 int set_prkey(struct config *conf, struct multipath *mpp, uint64_t prkey)
135 {
136         int fd;
137         int can_write = 1;
138         int ret = 1;
139         char keystr[PRKEY_SIZE];
140
141         if (!strlen(mpp->wwid))
142                 goto out;
143
144         fd = open_file(conf->prkeys_file, &can_write, PRKEYS_FILE_HEADER);
145         if (fd < 0)
146                 goto out;
147         if (!can_write) {
148                 condlog(0, "cannot set prkey, prkeys file is read-only");
149                 goto out_file;
150         }
151         if (prkey) {
152                 snprintf(keystr, PRKEY_SIZE, "0x%016" PRIx64, prkey);
153                 keystr[PRKEY_SIZE - 1] = '\0';
154                 ret = do_prkey(fd, mpp->wwid, keystr, PRKEY_WRITE);
155         }
156         else
157                 ret = do_prkey(fd, mpp->wwid, NULL, PRKEY_WRITE);
158         if (ret == 0)
159                 select_reservation_key(conf, mpp);
160         if (get_be64(mpp->reservation_key) != prkey)
161                 ret = 1;
162 out_file:
163         close(fd);
164 out:
165         return ret;
166 }