abd23c54afcdf0e157380917958d7aa4964c2947
[multipath-tools/.git] / libmultipath / wwids.c
1 #include <stdlib.h>
2 #include <errno.h>
3 #include <unistd.h>
4 #include <string.h>
5 #include <limits.h>
6 #include <stdio.h>
7
8 #include "checkers.h"
9 #include "vector.h"
10 #include "structs.h"
11 #include "debug.h"
12 #include "uxsock.h"
13 #include "file.h"
14 #include "wwids.h"
15 #include "defaults.h"
16 #include "config.h"
17
18 /*
19  * Copyright (c) 2010 Benjamin Marzinski, Redhat
20  */
21
22 static int
23 lookup_wwid(FILE *f, char *wwid) {
24         int c;
25         char buf[LINE_MAX];
26         int count;
27
28         while ((c = fgetc(f)) != EOF){
29                 if (c != '/') {
30                         if (fgets(buf, LINE_MAX, f) == NULL)
31                                 return 0;
32                         else
33                                 continue;
34                 }
35                 count = 0;
36                 while ((c = fgetc(f)) != '/') {
37                         if (c == EOF)
38                                 return 0;
39                         if (count >= WWID_SIZE - 1)
40                                 goto next;
41                         if (wwid[count] == '\0')
42                                 goto next;
43                         if (c != wwid[count++])
44                                 goto next;
45                 }
46                 if (wwid[count] == '\0')
47                         return 1;
48 next:
49                 if (fgets(buf, LINE_MAX, f) == NULL)
50                         return 0;
51         }
52         return 0;
53 }
54
55 static int
56 write_out_wwid(int fd, char *wwid) {
57         int ret;
58         off_t offset;
59         char buf[WWID_SIZE + 3];
60
61         ret = snprintf(buf, WWID_SIZE + 3, "/%s/\n", wwid);
62         if (ret >= (WWID_SIZE + 3) || ret < 0){
63                 condlog(0, "can't format wwid for writing (%d) : %s",
64                         ret, strerror(errno));
65                 return -1;
66         }
67         offset = lseek(fd, 0, SEEK_END);
68         if (offset < 0) {
69                 condlog(0, "can't seek to the end of wwids file : %s",
70                         strerror(errno));
71                 return -1;
72         }
73         if (write_all(fd, buf, strlen(buf)) != strlen(buf)) {
74                 condlog(0, "cannot write wwid to wwids file : %s",
75                         strerror(errno));
76                 if (ftruncate(fd, offset))
77                         condlog(0, "cannot truncate failed wwid write : %s",
78                                 strerror(errno));
79                 return -1;
80         }
81         return 1;
82 }
83
84 int
85 check_wwids_file(char *wwid, int write_wwid)
86 {
87         int fd, can_write, found, ret;
88         FILE *f;
89         fd = open_file(conf->wwids_file, &can_write, WWIDS_FILE_HEADER);
90         if (fd < 0)
91                 return -1;
92
93         f = fdopen(fd, "r");
94         if (!f) {
95                 condlog(0,"can't fdopen wwids file : %s", strerror(errno));
96                 close(fd);
97                 return -1;
98         }
99         found = lookup_wwid(f, wwid);
100         if (found) {
101                 ret = 0;
102                 goto out;
103         }
104         if (!write_wwid) {
105                 ret = -1;
106                 goto out;
107         }
108         if (!can_write) {
109                 condlog(0, "wwids file is read-only. Can't write wwid");
110                 ret = -1;
111                 goto out;
112         }
113
114         if (fflush(f) != 0) {
115                 condlog(0, "cannot fflush wwids file stream : %s",
116                         strerror(errno));
117                 ret = -1;
118                 goto out;
119         }
120
121         ret = write_out_wwid(fd, wwid);
122 out:
123         fclose(f);
124         return ret;
125 }
126
127 int
128 remember_wwid(char *wwid)
129 {
130         int ret = check_wwids_file(wwid, 1);
131         if (ret < 0){
132                 condlog(3, "failed writing wwid %s to wwids file", wwid);
133                 return -1;
134         }
135         if (ret == 1)
136                 condlog(3, "wrote wwid %s to wwids file", wwid);
137         else
138                 condlog(4, "wwid %s already in wwids file", wwid);
139         return 0;
140 }