2 * Copyright (c) 2005 Christophe Varoqui
3 * Copyright (c) 2005 Benjamin Marzinski, Redhat
21 #include "devmapper.h"
25 * significant parts of this file were taken from iscsi-bindings.c of the
26 * linux-iscsi project.
27 * Copyright (C) 2002 Cisco Systems, Inc.
29 * This program is free software; you can redistribute it and/or modify
30 * it under the terms of the GNU General Public License as published
31 * by the Free Software Foundation; either version 2 of the License, or
32 * (at your option) any later version.
34 * This program is distributed in the hope that it will be useful, but
35 * WITHOUT ANY WARRANTY; without even the implied warranty of
36 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
37 * General Public License for more details.
39 * See the file COPYING included with this distribution for more details.
42 #define BINDINGS_FILE_HEADER \
43 "# Multipath bindings, Version : 1.0\n" \
44 "# NOTE: this file is automatically maintained by the multipath program.\n" \
45 "# You should not need to edit this file in normal circumstances.\n" \
51 static const char bindings_file_header[] = BINDINGS_FILE_HEADER;
54 valid_alias(const char *alias)
56 if (strchr(alias, '/') != NULL)
61 static int format_devname(struct strbuf *buf, int id)
64 * We need: 7 chars for 32bit integers, 14 chars for 64bit integers
66 char devname[2 * sizeof(int)];
67 int pos = sizeof(devname) - 1, rc;
73 for (; id >= 1; id /= 26)
74 devname[--pos] = 'a' + --id % 26;
76 rc = append_strbuf_str(buf, devname + pos);
77 return rc >= 0 ? rc : -1;
81 scan_devname(const char *alias, const char *prefix)
85 static const int last_26 = INT_MAX / 26;
87 if (!prefix || strncmp(alias, prefix, strlen(prefix)))
90 if (strlen(alias) == strlen(prefix))
93 if (strlen(alias) > strlen(prefix) + 7)
94 /* id of 'aaaaaaaa' overflows int */
97 c = alias + strlen(prefix);
98 while (*c != '\0' && *c != ' ' && *c != '\t') {
99 if (*c < 'a' || *c > 'z')
102 if (n > last_26 || (n == last_26 && i >= INT_MAX % 26))
113 id_already_taken(int id, const char *prefix, const char *map_wwid)
115 STRBUF_ON_STACK(buf);
118 if (append_strbuf_str(&buf, prefix) < 0 ||
119 format_devname(&buf, id) < 0)
122 alias = get_strbuf_str(&buf);
123 if (dm_map_present(alias)) {
124 char wwid[WWID_SIZE];
126 /* If both the name and the wwid match, then it's fine.*/
127 if (dm_get_uuid(alias, wwid, sizeof(wwid)) == 0 &&
128 strncmp(map_wwid, wwid, sizeof(wwid)) == 0)
130 condlog(3, "%s: alias '%s' already taken, but not in bindings file. reselecting alias", map_wwid, alias);
138 * Returns: 0 if matching entry in WWIDs file found
139 * -1 if an error occurs
140 * >0 a free ID that could be used for the WWID at hand
141 * *map_alias is set to a freshly allocated string with the matching alias if
142 * the function returns 0, or to NULL otherwise.
145 lookup_binding(FILE *f, const char *map_wwid, char **map_alias,
146 const char *prefix, int check_if_taken)
149 unsigned int line_nr = 0;
152 int smallest_bigger_id = INT_MAX;
157 while (fgets(buf, LINE_MAX, f)) {
158 const char *alias, *wwid;
163 c = strpbrk(buf, "#\n\r");
166 alias = strtok_r(buf, " \t", &saveptr);
167 if (!alias) /* blank line */
169 curr_id = scan_devname(alias, prefix);
178 if (curr_id > biggest_id)
179 biggest_id = curr_id;
180 if (curr_id > id && curr_id < smallest_bigger_id)
181 smallest_bigger_id = curr_id;
182 wwid = strtok_r(NULL, " \t", &saveptr);
185 "Ignoring malformed line %u in bindings file",
189 if (strcmp(wwid, map_wwid) == 0){
190 condlog(3, "Found matching wwid [%s] in bindings file."
191 " Setting alias to %s", wwid, alias);
192 *map_alias = strdup(alias);
193 if (*map_alias == NULL) {
194 condlog(0, "Cannot copy alias from bindings "
195 "file: out of memory");
201 if (!prefix && check_if_taken)
203 if (id >= smallest_bigger_id) {
204 if (biggest_id < INT_MAX)
209 if (id > 0 && check_if_taken) {
210 while(id_already_taken(id, prefix, map_wwid)) {
216 if (id == smallest_bigger_id) {
217 if (biggest_id == INT_MAX) {
221 if (biggest_id >= smallest_bigger_id)
227 condlog(0, "no more available user_friendly_names");
230 condlog(3, "No matching wwid [%s] in bindings file.", map_wwid);
235 rlookup_binding(FILE *f, char *buff, const char *map_alias)
238 unsigned int line_nr = 0;
242 while (fgets(line, LINE_MAX, f)) {
244 const char *alias, *wwid;
247 c = strpbrk(line, "#\n\r");
250 alias = strtok_r(line, " \t", &saveptr);
251 if (!alias) /* blank line */
253 wwid = strtok_r(NULL, " \t", &saveptr);
256 "Ignoring malformed line %u in bindings file",
260 if (strlen(wwid) > WWID_SIZE - 1) {
262 "Ignoring too large wwid at %u in bindings file", line_nr);
265 if (strcmp(alias, map_alias) == 0){
266 condlog(3, "Found matching alias [%s] in bindings file."
267 " Setting wwid to %s", alias, wwid);
268 strlcpy(buff, wwid, WWID_SIZE);
272 condlog(3, "No matching alias [%s] in bindings file.", map_alias);
278 allocate_binding(int fd, const char *wwid, int id, const char *prefix)
280 STRBUF_ON_STACK(buf);
286 condlog(0, "%s: cannot allocate new binding for id %d",
291 if (append_strbuf_str(&buf, prefix) < 0 ||
292 format_devname(&buf, id) == -1)
295 if (print_strbuf(&buf, " %s\n", wwid) < 0)
298 offset = lseek(fd, 0, SEEK_END);
300 condlog(0, "Cannot seek to end of bindings file : %s",
305 len = get_strbuf_len(&buf);
306 alias = steal_strbuf_str(&buf);
308 if (write(fd, alias, len) != len) {
309 condlog(0, "Cannot write binding to bindings file : %s",
311 /* clear partial write */
312 if (ftruncate(fd, offset))
313 condlog(0, "Cannot truncate the header : %s",
318 c = strchr(alias, ' ');
322 condlog(3, "Created new binding [%s] for WWID [%s]", alias, wwid);
327 use_existing_alias (const char *wwid, const char *file, const char *alias_old,
328 const char *prefix, int bindings_read_only)
333 char buff[WWID_SIZE];
336 fd = open_file(file, &can_write, bindings_file_header);
342 condlog(0, "cannot fdopen on bindings file descriptor");
346 /* lookup the binding. if it exists, the wwid will be in buff
347 * either way, id contains the id for the alias
349 rlookup_binding(f, buff, alias_old);
351 if (strlen(buff) > 0) {
352 /* if buff is our wwid, it's already
353 * allocated correctly
355 if (strcmp(buff, wwid) == 0)
356 alias = strdup(alias_old);
359 condlog(0, "alias %s already bound to wwid %s, cannot reuse",
365 id = lookup_binding(f, wwid, &alias, NULL, 0);
367 condlog(3, "Use existing binding [%s] for WWID [%s]",
372 /* allocate the existing alias in the bindings file */
373 id = scan_devname(alias_old, prefix);
377 if (fflush(f) != 0) {
378 condlog(0, "cannot fflush bindings file stream : %s",
383 if (can_write && !bindings_read_only) {
384 alias = allocate_binding(fd, wwid, id, prefix);
385 condlog(0, "Allocated existing binding [%s] for WWID [%s]",
390 pthread_cleanup_push(free, alias);
392 pthread_cleanup_pop(0);
397 get_user_friendly_alias(const char *wwid, const char *file, const char *prefix,
398 int bindings_read_only)
405 if (!wwid || *wwid == '\0') {
406 condlog(3, "Cannot find binding for empty WWID");
410 fd = open_file(file, &can_write, bindings_file_header);
416 condlog(0, "cannot fdopen on bindings file descriptor : %s",
422 id = lookup_binding(f, wwid, &alias, prefix, 1);
428 pthread_cleanup_push(free, alias);
430 if (fflush(f) != 0) {
431 condlog(0, "cannot fflush bindings file stream : %s",
435 } else if (can_write && !bindings_read_only && !alias)
436 alias = allocate_binding(fd, wwid, id, prefix);
440 pthread_cleanup_pop(0);
445 get_user_friendly_wwid(const char *alias, char *buff, const char *file)
450 if (!alias || *alias == '\0') {
451 condlog(3, "Cannot find binding for empty alias");
455 fd = open_file(file, &unused, bindings_file_header);
461 condlog(0, "cannot fdopen on bindings file descriptor : %s",
467 rlookup_binding(f, buff, alias);
482 static void _free_binding(struct binding *bdg)
490 * Perhaps one day we'll implement this more efficiently, thus use
493 typedef struct _vector Bindings;
495 static void free_bindings(Bindings *bindings)
500 vector_foreach_slot(bindings, bdg, i)
502 vector_reset(bindings);
514 static int add_binding(Bindings *bindings, const char *alias, const char *wwid)
520 * Keep the bindings array sorted by alias.
521 * Optimization: Search backwards, assuming that the bindings file is
524 vector_foreach_slot_backwards(bindings, bdg, i) {
525 if ((cmp = strcmp(bdg->alias, alias)) <= 0)
529 /* Check for exact match */
530 if (i >= 0 && cmp == 0)
531 return strcmp(bdg->wwid, wwid) ?
532 BINDING_CONFLICT : BINDING_EXISTS;
535 bdg = calloc(1, sizeof(*bdg));
537 bdg->wwid = strdup(wwid);
538 bdg->alias = strdup(alias);
539 if (bdg->wwid && bdg->alias &&
540 vector_insert_slot(bindings, i, bdg))
541 return BINDING_ADDED;
546 return BINDING_ERROR;
549 static int write_bindings_file(const Bindings *bindings, int fd)
552 STRBUF_ON_STACK(line);
555 if (write(fd, BINDINGS_FILE_HEADER, sizeof(BINDINGS_FILE_HEADER) - 1)
556 != sizeof(BINDINGS_FILE_HEADER) - 1)
559 vector_foreach_slot(bindings, bnd, i) {
562 if ((len = print_strbuf(&line, "%s %s\n",
563 bnd->alias, bnd->wwid)) < 0)
565 if (write(fd, get_strbuf_str(&line), len) != len)
567 truncate_strbuf(&line, 0);
572 static int fix_bindings_file(const struct config *conf,
573 const Bindings *bindings)
577 char tempname[PATH_MAX];
580 if (safe_sprintf(tempname, "%s.XXXXXX", conf->bindings_file))
582 /* coverity: SECURE_TEMP */
583 old_umask = umask(0077);
584 if ((fd = mkstemp(tempname)) == -1) {
585 condlog(1, "%s: mkstemp: %m", __func__);
589 pthread_cleanup_push(close_fd, (void*)fd);
590 rc = write_bindings_file(bindings, fd);
591 pthread_cleanup_pop(1);
593 condlog(1, "failed to write new bindings file %s",
598 if ((rc = rename(tempname, conf->bindings_file)) == -1)
599 condlog(0, "%s: rename: %m", __func__);
601 condlog(1, "updated bindings file %s", conf->bindings_file);
605 static int _check_bindings_file(const struct config *conf, FILE *file,
609 unsigned int linenr = 0;
614 pthread_cleanup_push(cleanup_free_ptr, &line);
615 while ((n = getline(&line, &line_len, file)) >= 0) {
616 char *c, *alias, *wwid, *saveptr;
617 const char *mpe_wwid;
620 c = strpbrk(line, "#\n\r");
623 alias = strtok_r(line, " \t", &saveptr);
624 if (!alias) /* blank line */
626 wwid = strtok_r(NULL, " \t", &saveptr);
628 condlog(1, "invalid line %d in bindings file, missing WWID",
632 c = strtok_r(NULL, " \t", &saveptr);
634 /* This is non-fatal */
635 condlog(1, "invalid line %d in bindings file, extra args \"%s\"",
638 mpe_wwid = get_mpe_wwid(conf->mptable, alias);
639 if (mpe_wwid && strcmp(mpe_wwid, wwid)) {
640 condlog(0, "ERROR: alias \"%s\" for WWID %s in bindings file "
641 "on line %u conflicts with multipath.conf entry for %s",
642 alias, wwid, linenr, mpe_wwid);
647 switch (add_binding(bindings, alias, wwid)) {
648 case BINDING_CONFLICT:
649 condlog(0, "ERROR: multiple bindings for alias \"%s\" in "
650 "bindings file on line %u, discarding binding to WWID %s",
651 alias, linenr, wwid);
655 condlog(2, "duplicate line for alias %s in bindings file on line %u",
659 condlog(2, "error adding binding %s -> %s",
666 pthread_cleanup_pop(1);
670 static void cleanup_fclose(void *p)
676 * check_alias_settings(): test for inconsistent alias configuration
678 * It's a fatal configuration error if the same alias is assigned to
679 * multiple WWIDs. In the worst case, it can cause data corruption
680 * by mangling devices with different WWIDs into the same multipath map.
681 * This function tests the configuration from multipath.conf and the
682 * bindings file for consistency, drops inconsistent multipath.conf
683 * alias settings, and rewrites the bindings file if necessary, dropping
684 * conflicting lines (if user_friendly_names is on, multipathd will
685 * fill in the deleted lines with a newly generated alias later).
686 * Note that multipath.conf is not rewritten. Use "multipath -T" for that.
688 * Returns: 0 in case of success, -1 if the configuration was bad
689 * and couldn't be fixed.
691 int check_alias_settings(const struct config *conf)
695 Bindings bindings = {.allocated = 0, };
698 pthread_cleanup_push_cast(free_bindings, &bindings);
699 vector_foreach_slot(conf->mptable, mpe, i) {
700 if (!mpe->wwid || !mpe->alias)
702 if (add_binding(&bindings, mpe->alias, mpe->wwid) ==
704 condlog(0, "ERROR: alias \"%s\" bound to multiple wwids in multipath.conf, "
705 "discarding binding to %s",
706 mpe->alias, mpe->wwid);
711 /* This clears the bindings */
712 pthread_cleanup_pop(1);
714 pthread_cleanup_push_cast(free_bindings, &bindings);
715 fd = open_file(conf->bindings_file, &can_write, BINDINGS_FILE_HEADER);
717 FILE *file = fdopen(fd, "r");
720 pthread_cleanup_push(cleanup_fclose, file);
721 rc = _check_bindings_file(conf, file, &bindings);
722 pthread_cleanup_pop(1);
723 if (rc == -1 && can_write && !conf->bindings_read_only)
724 rc = fix_bindings_file(conf, &bindings);
726 condlog(0, "ERROR: bad settings in read-only bindings file %s",
727 conf->bindings_file);
729 condlog(1, "failed to fdopen %s: %m",
730 conf->bindings_file);
734 pthread_cleanup_pop(1);