2 * Copyright (C) 2005-2006 Kay Sievers <kay.sievers@vrfy.org>
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.
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.
13 * You should have received a copy of the GNU General Public License along
14 * with this program. If not, see <http://www.gnu.org/licenses/>.
40 #include "devmapper.h"
43 * When we modify an attribute value we cannot rely on libudev for now,
44 * as libudev lacks the capability to update an attribute value.
45 * So for modified attributes we need to implement our own function.
47 ssize_t sysfs_attr_get_value(struct udev_device *dev, const char *attr_name,
48 char * value, size_t value_len)
50 char devpath[PATH_SIZE];
55 if (!dev || !attr_name || !value)
58 snprintf(devpath, PATH_SIZE, "%s/%s", udev_device_get_syspath(dev),
60 condlog(4, "open '%s'", devpath);
61 /* read attribute value */
62 fd = open(devpath, O_RDONLY);
64 condlog(4, "attribute '%s' can not be opened: %s",
65 devpath, strerror(errno));
68 if (fstat(fd, &statbuf) < 0) {
69 condlog(4, "stat '%s' failed: %s", devpath, strerror(errno));
73 /* skip directories */
74 if (S_ISDIR(statbuf.st_mode)) {
75 condlog(4, "%s is a directory", devpath);
79 /* skip non-writeable files */
80 if ((statbuf.st_mode & S_IRUSR) == 0) {
81 condlog(4, "%s is not readable", devpath);
86 size = read(fd, value, value_len);
88 condlog(4, "read from %s failed: %s", devpath, strerror(errno));
91 } else if (size == value_len) {
92 value[size - 1] = '\0';
93 condlog(4, "overflow while reading from %s", devpath);
97 size = strchop(value);
104 ssize_t sysfs_bin_attr_get_value(struct udev_device *dev, const char *attr_name,
105 unsigned char * value, size_t value_len)
107 char devpath[PATH_SIZE];
112 if (!dev || !attr_name || !value)
115 snprintf(devpath, PATH_SIZE, "%s/%s", udev_device_get_syspath(dev),
117 condlog(4, "open '%s'", devpath);
118 /* read attribute value */
119 fd = open(devpath, O_RDONLY);
121 condlog(4, "attribute '%s' can not be opened: %s",
122 devpath, strerror(errno));
125 if (fstat(fd, &statbuf) != 0) {
126 condlog(4, "stat '%s' failed: %s", devpath, strerror(errno));
131 /* skip directories */
132 if (S_ISDIR(statbuf.st_mode)) {
133 condlog(4, "%s is a directory", devpath);
138 /* skip non-writeable files */
139 if ((statbuf.st_mode & S_IRUSR) == 0) {
140 condlog(4, "%s is not readable", devpath);
145 size = read(fd, value, value_len);
147 condlog(4, "read from %s failed: %s", devpath, strerror(errno));
149 } else if (size == value_len) {
150 condlog(4, "overflow while reading from %s", devpath);
158 ssize_t sysfs_attr_set_value(struct udev_device *dev, const char *attr_name,
159 const char * value, size_t value_len)
161 char devpath[PATH_SIZE];
166 if (!dev || !attr_name || !value || !value_len)
169 snprintf(devpath, PATH_SIZE, "%s/%s", udev_device_get_syspath(dev),
171 condlog(4, "open '%s'", devpath);
172 /* write attribute value */
173 fd = open(devpath, O_WRONLY);
175 condlog(4, "attribute '%s' can not be opened: %s",
176 devpath, strerror(errno));
179 if (fstat(fd, &statbuf) != 0) {
180 condlog(4, "stat '%s' failed: %s", devpath, strerror(errno));
185 /* skip directories */
186 if (S_ISDIR(statbuf.st_mode)) {
187 condlog(4, "%s is a directory", devpath);
192 /* skip non-writeable files */
193 if ((statbuf.st_mode & S_IWUSR) == 0) {
194 condlog(4, "%s is not writeable", devpath);
199 size = write(fd, value, value_len);
201 condlog(4, "write to %s failed: %s", devpath, strerror(errno));
203 } else if (size < value_len) {
204 condlog(4, "tried to write %ld to %s. Wrote %ld",
205 (long)value_len, devpath, (long)size);
214 sysfs_get_size (struct path *pp, unsigned long long * size)
219 if (!pp->udev || !size)
223 if (sysfs_attr_get_value(pp->udev, "size", attr, 255) <= 0) {
224 condlog(3, "%s: No size attribute in sysfs", pp->dev);
228 r = sscanf(attr, "%llu\n", size);
231 condlog(3, "%s: Cannot parse size attribute", pp->dev);
239 int sysfs_check_holders(char * check_devt, char * new_devt)
241 unsigned int major, new_minor, table_minor;
242 char path[PATH_MAX], check_dev[PATH_SIZE];
245 struct dirent *holder;
247 if (sscanf(new_devt,"%d:%d", &major, &new_minor) != 2) {
248 condlog(1, "invalid device number %s", new_devt);
252 if (devt2devname(check_dev, PATH_SIZE, check_devt)) {
253 condlog(1, "can't get devname for %s", check_devt);
257 condlog(3, "%s: checking holder", check_dev);
259 snprintf(path, sizeof(path), "/sys/block/%s/holders", check_dev);
260 dirfd = opendir(path);
262 condlog(3, "%s: failed to open directory %s (%d)",
263 check_dev, path, errno);
266 while ((holder = readdir(dirfd)) != NULL) {
267 if ((strcmp(holder->d_name,".") == 0) ||
268 (strcmp(holder->d_name,"..") == 0))
271 if (sscanf(holder->d_name, "dm-%d", &table_minor) != 1) {
272 condlog(3, "%s: %s is not a dm-device",
273 check_dev, holder->d_name);
276 if (table_minor == new_minor) {
277 condlog(3, "%s: holder already correct", check_dev);
280 table_name = dm_mapname(major, table_minor);
282 condlog(0, "%s: reassign table %s old %s new %s", check_dev,
283 table_name, check_devt, new_devt);
285 dm_reassign_table(table_name, check_devt, new_devt);
293 static int select_dm_devs(const struct dirent *di)
295 return fnmatch("dm-*", di->d_name, FNM_FILE_NAME) == 0;
298 static void close_fd(void *arg)
303 bool sysfs_is_multipathed(const struct path *pp)
305 char pathbuf[PATH_MAX];
306 struct scandir_result sr;
311 n = snprintf(pathbuf, sizeof(pathbuf), "/sys/block/%s/holders",
314 if (n >= sizeof(pathbuf)) {
315 condlog(1, "%s: pathname overflow", __func__);
319 r = scandir(pathbuf, &di, select_dm_devs, alphasort);
323 condlog(1, "%s: error scanning %s", __func__, pathbuf);
329 pthread_cleanup_push_cast(free_scandir_result, &sr);
330 for (i = 0; i < r && !found; i++) {
335 if (snprintf(pathbuf + n, sizeof(pathbuf) - n,
336 "/%s/dm/uuid", di[i]->d_name)
337 >= sizeof(pathbuf) - n)
340 fd = open(pathbuf, O_RDONLY);
342 condlog(1, "%s: error opening %s", __func__, pathbuf);
346 pthread_cleanup_push(close_fd, (void *)fd);
347 nr = read(fd, uuid, sizeof(uuid));
348 if (nr == sizeof(uuid) && !memcmp(uuid, "mpath-", sizeof(uuid)))
351 condlog(1, "%s: error reading from %s: %s",
352 __func__, pathbuf, strerror(errno));
354 pthread_cleanup_pop(1);
356 pthread_cleanup_pop(1);