Do not print error when rport is blocked
[multipath-tools/.git] / libmultipath / sysfs.c
1 /*
2  * Copyright (C) 2005-2006 Kay Sievers <kay.sievers@vrfy.org>
3  *
4  *      This program is free software; you can redistribute it and/or modify it
5  *      under the terms of the GNU General Public License as published by the
6  *      Free Software Foundation version 2 of the License.
7  *
8  *      This program is distributed in the hope that it will be useful, but
9  *      WITHOUT ANY WARRANTY; without even the implied warranty of
10  *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11  *      General Public License for more details.
12  *
13  *      You should have received a copy of the GNU General Public License along
14  *      with this program; if not, write to the Free Software Foundation, Inc.,
15  *      51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
16  *
17  */
18
19
20 #include <stdlib.h>
21 #include <stdio.h>
22 #include <stddef.h>
23 #include <unistd.h>
24 #include <fcntl.h>
25 #include <ctype.h>
26 #include <errno.h>
27 #include <sys/stat.h>
28 #include <string.h>
29 #include <dirent.h>
30 #include <libudev.h>
31
32 #include "checkers.h"
33 #include "vector.h"
34 #include "structs.h"
35 #include "sysfs.h"
36 #include "list.h"
37 #include "util.h"
38 #include "debug.h"
39 #include "devmapper.h"
40
41 /*
42  * When we modify an attribute value we cannot rely on libudev for now,
43  * as libudev lacks the capability to update an attribute value.
44  * So for modified attributes we need to implement our own function.
45  */
46 ssize_t sysfs_attr_get_value(struct udev_device *dev, const char *attr_name,
47                              char * value, size_t value_len)
48 {
49         char devpath[PATH_SIZE];
50         struct stat statbuf;
51         int fd;
52         ssize_t size = -1;
53
54         if (!dev || !attr_name || !value)
55                 return 0;
56
57         snprintf(devpath, PATH_SIZE, "%s/%s", udev_device_get_syspath(dev),
58                  attr_name);
59         condlog(4, "open '%s'", devpath);
60         if (stat(devpath, &statbuf) != 0) {
61                 condlog(4, "stat '%s' failed: %s", devpath, strerror(errno));
62                 return -errno;
63         }
64
65         /* skip directories */
66         if (S_ISDIR(statbuf.st_mode)) {
67                 condlog(4, "%s is a directory", devpath);
68                 return -EISDIR;
69         }
70
71         /* skip non-writeable files */
72         if ((statbuf.st_mode & S_IRUSR) == 0) {
73                 condlog(4, "%s is not readable", devpath);
74                 return -EPERM;
75         }
76
77         /* read attribute value */
78         fd = open(devpath, O_RDONLY);
79         if (fd < 0) {
80                 condlog(4, "attribute '%s' can not be opened: %s",
81                         devpath, strerror(errno));
82                 return -errno;
83         }
84         size = read(fd, value, value_len);
85         if (size < 0) {
86                 condlog(4, "read from %s failed: %s", devpath, strerror(errno));
87                 size = -errno;
88         } else if (size == value_len) {
89                 condlog(4, "overflow while reading from %s", devpath);
90                 size = 0;
91         }
92
93         close(fd);
94         return size;
95 }
96
97 ssize_t sysfs_attr_set_value(struct udev_device *dev, const char *attr_name,
98                              char * value, size_t value_len)
99 {
100         char devpath[PATH_SIZE];
101         struct stat statbuf;
102         int fd;
103         ssize_t size = -1;
104
105         if (!dev || !attr_name || !value)
106                 return 0;
107
108         snprintf(devpath, PATH_SIZE, "%s/%s", udev_device_get_syspath(dev),
109                  attr_name);
110         condlog(4, "open '%s'", devpath);
111         if (stat(devpath, &statbuf) != 0) {
112                 condlog(4, "stat '%s' failed: %s", devpath, strerror(errno));
113                 return -errno;
114         }
115
116         /* skip directories */
117         if (S_ISDIR(statbuf.st_mode)) {
118                 condlog(4, "%s is a directory", devpath);
119                 return -EISDIR;
120         }
121
122         /* skip non-writeable files */
123         if ((statbuf.st_mode & S_IWUSR) == 0) {
124                 condlog(4, "%s is not writeable", devpath);
125                 return -EPERM;
126         }
127
128         /* write attribute value */
129         fd = open(devpath, O_WRONLY);
130         if (fd < 0) {
131                 condlog(4, "attribute '%s' can not be opened: %s",
132                         devpath, strerror(errno));
133                 return -errno;
134         }
135         size = write(fd, value, value_len);
136         if (size < 0) {
137                 condlog(4, "write to %s failed: %s", devpath, strerror(errno));
138                 size = -errno;
139         } else if (size < value_len) {
140                 condlog(4, "tried to write %ld to %s. Wrote %ld",
141                         (long)value_len, devpath, (long)size);
142                 size = 0;
143         }
144
145         close(fd);
146         return size;
147 }
148
149 int
150 sysfs_get_size (struct path *pp, unsigned long long * size)
151 {
152         char attr[255];
153         int r;
154
155         if (!pp->udev)
156                 return 1;
157
158         if (sysfs_attr_get_value(pp->udev, "size", attr, 255) == 0) {
159                 condlog(3, "%s: No size attribute in sysfs", pp->dev);
160                 return 1;
161         }
162
163         r = sscanf(attr, "%llu\n", size);
164
165         if (r != 1) {
166                 condlog(3, "%s: Cannot parse size attribute", pp->dev);
167                 return 1;
168         }
169
170         return 0;
171 }
172
173 int sysfs_check_holders(char * check_devt, char * new_devt)
174 {
175         unsigned int major, new_minor, table_minor;
176         char path[PATH_SIZE], check_dev[PATH_SIZE];
177         char * table_name;
178         DIR *dirfd;
179         struct dirent *holder;
180
181         if (sscanf(new_devt,"%d:%d", &major, &new_minor) != 2) {
182                 condlog(1, "invalid device number %s", new_devt);
183                 return 0;
184         }
185
186         if (devt2devname(check_dev, PATH_SIZE, check_devt)) {
187                 condlog(1, "can't get devname for %s", check_devt);
188                 return 0;
189         }
190
191         condlog(3, "%s: checking holder", check_dev);
192
193         snprintf(path, PATH_SIZE, "/sys/block/%s/holders", check_dev);
194         dirfd = opendir(path);
195         if (dirfd == NULL) {
196                 condlog(3, "%s: failed to open directory %s (%d)",
197                         check_dev, path, errno);
198                 return 0;
199         }
200         while ((holder = readdir(dirfd)) != NULL) {
201                 if ((strcmp(holder->d_name,".") == 0) ||
202                     (strcmp(holder->d_name,"..") == 0))
203                         continue;
204
205                 if (sscanf(holder->d_name, "dm-%d", &table_minor) != 1) {
206                         condlog(3, "%s: %s is not a dm-device",
207                                 check_dev, holder->d_name);
208                         continue;
209                 }
210                 if (table_minor == new_minor) {
211                         condlog(3, "%s: holder already correct", check_dev);
212                         continue;
213                 }
214                 table_name = dm_mapname(major, table_minor);
215
216                 condlog(0, "%s: reassign table %s old %s new %s", check_dev,
217                         table_name, check_devt, new_devt);
218
219                 dm_reassign_table(table_name, check_devt, new_devt);
220                 FREE(table_name);
221         }
222         closedir(dirfd);
223
224         return 0;
225 }