Imported Upstream version 0.8.9
[platform/upstream/multipath-tools.git] / libmultipath / alias.c
1 /*
2  * Copyright (c) 2005 Christophe Varoqui
3  * Copyright (c) 2005 Benjamin Marzinski, Redhat
4  */
5 #include <stdlib.h>
6 #include <errno.h>
7 #include <unistd.h>
8 #include <string.h>
9 #include <limits.h>
10 #include <stdio.h>
11
12 #include "debug.h"
13 #include "util.h"
14 #include "uxsock.h"
15 #include "alias.h"
16 #include "file.h"
17 #include "vector.h"
18 #include "checkers.h"
19 #include "structs.h"
20 #include "config.h"
21 #include "devmapper.h"
22 #include "strbuf.h"
23
24 /*
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.
28  *
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.
33  *
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.
38  *
39  * See the file COPYING included with this distribution for more details.
40  */
41
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" \
46 "#\n" \
47 "# Format:\n" \
48 "# alias wwid\n" \
49 "#\n"
50
51 static const char bindings_file_header[] = BINDINGS_FILE_HEADER;
52
53 int
54 valid_alias(const char *alias)
55 {
56         if (strchr(alias, '/') != NULL)
57                 return 0;
58         return 1;
59 }
60
61 static int format_devname(struct strbuf *buf, int id)
62 {
63         /*
64          * We need: 7 chars for 32bit integers, 14 chars for 64bit integers
65          */
66         char devname[2 * sizeof(int)];
67         int pos = sizeof(devname) - 1, rc;
68
69         if (id <= 0)
70                 return -1;
71
72         devname[pos] = '\0';
73         for (; id >= 1; id /= 26)
74                 devname[--pos] = 'a' + --id % 26;
75
76         rc = append_strbuf_str(buf, devname + pos);
77         return rc >= 0 ? rc : -1;
78 }
79
80 static int
81 scan_devname(const char *alias, const char *prefix)
82 {
83         const char *c;
84         int i, n = 0;
85         static const int last_26 = INT_MAX / 26;
86
87         if (!prefix || strncmp(alias, prefix, strlen(prefix)))
88                 return -1;
89
90         if (strlen(alias) == strlen(prefix))
91                 return -1;
92
93         if (strlen(alias) > strlen(prefix) + 7)
94                 /* id of 'aaaaaaaa' overflows int */
95                 return -1;
96
97         c = alias + strlen(prefix);
98         while (*c != '\0' && *c != ' ' && *c != '\t') {
99                 if (*c < 'a' || *c > 'z')
100                         return -1;
101                 i = *c - 'a';
102                 if (n > last_26 || (n == last_26 && i >= INT_MAX % 26))
103                         return -1;
104                 n = n * 26 + i;
105                 c++;
106                 n++;
107         }
108
109         return n;
110 }
111
112 static int
113 id_already_taken(int id, const char *prefix, const char *map_wwid)
114 {
115         STRBUF_ON_STACK(buf);
116         const char *alias;
117
118         if (append_strbuf_str(&buf, prefix) < 0 ||
119             format_devname(&buf, id) < 0)
120                 return 0;
121
122         alias = get_strbuf_str(&buf);
123         if (dm_map_present(alias)) {
124                 char wwid[WWID_SIZE];
125
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)
129                         return 0;
130                 condlog(3, "%s: alias '%s' already taken, but not in bindings file. reselecting alias", map_wwid, alias);
131                 return 1;
132         }
133         return 0;
134 }
135
136
137 /*
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.
143  */
144 static int
145 lookup_binding(FILE *f, const char *map_wwid, char **map_alias,
146                const char *prefix, int check_if_taken)
147 {
148         char buf[LINE_MAX];
149         unsigned int line_nr = 0;
150         int id = 1;
151         int biggest_id = 1;
152         int smallest_bigger_id = INT_MAX;
153
154         *map_alias = NULL;
155
156         rewind(f);
157         while (fgets(buf, LINE_MAX, f)) {
158                 const char *alias, *wwid;
159                 char *c, *saveptr;
160                 int curr_id;
161
162                 line_nr++;
163                 c = strpbrk(buf, "#\n\r");
164                 if (c)
165                         *c = '\0';
166                 alias = strtok_r(buf, " \t", &saveptr);
167                 if (!alias) /* blank line */
168                         continue;
169                 curr_id = scan_devname(alias, prefix);
170                 if (curr_id == id) {
171                         if (id < INT_MAX)
172                                 id++;
173                         else {
174                                 id = -1;
175                                 break;
176                         }
177                 }
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);
183                 if (!wwid){
184                         condlog(3,
185                                 "Ignoring malformed line %u in bindings file",
186                                 line_nr);
187                         continue;
188                 }
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");
196                                 return -1;
197                         }
198                         return 0;
199                 }
200         }
201         if (!prefix && check_if_taken)
202                 id = -1;
203         if (id >= smallest_bigger_id) {
204                 if (biggest_id < INT_MAX)
205                         id = biggest_id + 1;
206                 else
207                         id = -1;
208         }
209         if (id > 0 && check_if_taken) {
210                 while(id_already_taken(id, prefix, map_wwid)) {
211                         if (id == INT_MAX) {
212                                 id = -1;
213                                 break;
214                         }
215                         id++;
216                         if (id == smallest_bigger_id) {
217                                 if (biggest_id == INT_MAX) {
218                                         id = -1;
219                                         break;
220                                 }
221                                 if (biggest_id >= smallest_bigger_id)
222                                         id = biggest_id + 1;
223                         }
224                 }
225         }
226         if (id < 0) {
227                 condlog(0, "no more available user_friendly_names");
228                 return -1;
229         } else
230                 condlog(3, "No matching wwid [%s] in bindings file.", map_wwid);
231         return id;
232 }
233
234 static int
235 rlookup_binding(FILE *f, char *buff, const char *map_alias)
236 {
237         char line[LINE_MAX];
238         unsigned int line_nr = 0;
239
240         buff[0] = '\0';
241
242         while (fgets(line, LINE_MAX, f)) {
243                 char *c, *saveptr;
244                 const char *alias, *wwid;
245
246                 line_nr++;
247                 c = strpbrk(line, "#\n\r");
248                 if (c)
249                         *c = '\0';
250                 alias = strtok_r(line, " \t", &saveptr);
251                 if (!alias) /* blank line */
252                         continue;
253                 wwid = strtok_r(NULL, " \t", &saveptr);
254                 if (!wwid){
255                         condlog(3,
256                                 "Ignoring malformed line %u in bindings file",
257                                 line_nr);
258                         continue;
259                 }
260                 if (strlen(wwid) > WWID_SIZE - 1) {
261                         condlog(3,
262                                 "Ignoring too large wwid at %u in bindings file", line_nr);
263                         continue;
264                 }
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);
269                         return 0;
270                 }
271         }
272         condlog(3, "No matching alias [%s] in bindings file.", map_alias);
273
274         return -1;
275 }
276
277 static char *
278 allocate_binding(int fd, const char *wwid, int id, const char *prefix)
279 {
280         STRBUF_ON_STACK(buf);
281         off_t offset;
282         ssize_t len;
283         char *alias, *c;
284
285         if (id <= 0) {
286                 condlog(0, "%s: cannot allocate new binding for id %d",
287                         __func__, id);
288                 return NULL;
289         }
290
291         if (append_strbuf_str(&buf, prefix) < 0 ||
292             format_devname(&buf, id) == -1)
293                 return NULL;
294
295         if (print_strbuf(&buf, " %s\n", wwid) < 0)
296                 return NULL;
297
298         offset = lseek(fd, 0, SEEK_END);
299         if (offset < 0){
300                 condlog(0, "Cannot seek to end of bindings file : %s",
301                         strerror(errno));
302                 return NULL;
303         }
304
305         len = get_strbuf_len(&buf);
306         alias = steal_strbuf_str(&buf);
307
308         if (write(fd, alias, len) != len) {
309                 condlog(0, "Cannot write binding to bindings file : %s",
310                         strerror(errno));
311                 /* clear partial write */
312                 if (ftruncate(fd, offset))
313                         condlog(0, "Cannot truncate the header : %s",
314                                 strerror(errno));
315                 free(alias);
316                 return NULL;
317         }
318         c = strchr(alias, ' ');
319         if (c)
320                 *c = '\0';
321
322         condlog(3, "Created new binding [%s] for WWID [%s]", alias, wwid);
323         return alias;
324 }
325
326 char *
327 use_existing_alias (const char *wwid, const char *file, const char *alias_old,
328                     const char *prefix, int bindings_read_only)
329 {
330         char *alias = NULL;
331         int id = 0;
332         int fd, can_write;
333         char buff[WWID_SIZE];
334         FILE *f;
335
336         fd = open_file(file, &can_write, bindings_file_header);
337         if (fd < 0)
338                 return NULL;
339
340         f = fdopen(fd, "r");
341         if (!f) {
342                 condlog(0, "cannot fdopen on bindings file descriptor");
343                 close(fd);
344                 return NULL;
345         }
346         /* lookup the binding. if it exists, the wwid will be in buff
347          * either way, id contains the id for the alias
348          */
349         rlookup_binding(f, buff, alias_old);
350
351         if (strlen(buff) > 0) {
352                 /* if buff is our wwid, it's already
353                  * allocated correctly
354                  */
355                 if (strcmp(buff, wwid) == 0)
356                         alias = strdup(alias_old);
357                 else {
358                         alias = NULL;
359                         condlog(0, "alias %s already bound to wwid %s, cannot reuse",
360                                 alias_old, buff);
361                 }
362                 goto out;
363         }
364
365         id = lookup_binding(f, wwid, &alias, NULL, 0);
366         if (alias) {
367                 condlog(3, "Use existing binding [%s] for WWID [%s]",
368                         alias, wwid);
369                 goto out;
370         }
371
372         /* allocate the existing alias in the bindings file */
373         id = scan_devname(alias_old, prefix);
374         if (id <= 0)
375                 goto out;
376
377         if (fflush(f) != 0) {
378                 condlog(0, "cannot fflush bindings file stream : %s",
379                         strerror(errno));
380                 goto out;
381         }
382
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]",
386                         alias, wwid);
387         }
388
389 out:
390         pthread_cleanup_push(free, alias);
391         fclose(f);
392         pthread_cleanup_pop(0);
393         return alias;
394 }
395
396 char *
397 get_user_friendly_alias(const char *wwid, const char *file, const char *prefix,
398                         int bindings_read_only)
399 {
400         char *alias;
401         int fd, id;
402         FILE *f;
403         int can_write;
404
405         if (!wwid || *wwid == '\0') {
406                 condlog(3, "Cannot find binding for empty WWID");
407                 return NULL;
408         }
409
410         fd = open_file(file, &can_write, bindings_file_header);
411         if (fd < 0)
412                 return NULL;
413
414         f = fdopen(fd, "r");
415         if (!f) {
416                 condlog(0, "cannot fdopen on bindings file descriptor : %s",
417                         strerror(errno));
418                 close(fd);
419                 return NULL;
420         }
421
422         id = lookup_binding(f, wwid, &alias, prefix, 1);
423         if (id < 0) {
424                 fclose(f);
425                 return NULL;
426         }
427
428         pthread_cleanup_push(free, alias);
429
430         if (fflush(f) != 0) {
431                 condlog(0, "cannot fflush bindings file stream : %s",
432                         strerror(errno));
433                 free(alias);
434                 alias = NULL;
435         } else if (can_write && !bindings_read_only && !alias)
436                 alias = allocate_binding(fd, wwid, id, prefix);
437
438         fclose(f);
439
440         pthread_cleanup_pop(0);
441         return alias;
442 }
443
444 int
445 get_user_friendly_wwid(const char *alias, char *buff, const char *file)
446 {
447         int fd, unused;
448         FILE *f;
449
450         if (!alias || *alias == '\0') {
451                 condlog(3, "Cannot find binding for empty alias");
452                 return -1;
453         }
454
455         fd = open_file(file, &unused, bindings_file_header);
456         if (fd < 0)
457                 return -1;
458
459         f = fdopen(fd, "r");
460         if (!f) {
461                 condlog(0, "cannot fdopen on bindings file descriptor : %s",
462                         strerror(errno));
463                 close(fd);
464                 return -1;
465         }
466
467         rlookup_binding(f, buff, alias);
468         if (!strlen(buff)) {
469                 fclose(f);
470                 return -1;
471         }
472
473         fclose(f);
474         return 0;
475 }
476
477 struct binding {
478         char *alias;
479         char *wwid;
480 };
481
482 static void _free_binding(struct binding *bdg)
483 {
484         free(bdg->wwid);
485         free(bdg->alias);
486         free(bdg);
487 }
488
489 /*
490  * Perhaps one day we'll implement this more efficiently, thus use
491  * an abstract type.
492  */
493 typedef struct _vector Bindings;
494
495 static void free_bindings(Bindings *bindings)
496 {
497         struct binding *bdg;
498         int i;
499
500         vector_foreach_slot(bindings, bdg, i)
501                 _free_binding(bdg);
502         vector_reset(bindings);
503 }
504
505 enum {
506         BINDING_EXISTS,
507         BINDING_CONFLICT,
508         BINDING_ADDED,
509         BINDING_DELETED,
510         BINDING_NOTFOUND,
511         BINDING_ERROR,
512 };
513
514 static int add_binding(Bindings *bindings, const char *alias, const char *wwid)
515 {
516         struct binding *bdg;
517         int i, cmp = 0;
518
519         /*
520          * Keep the bindings array sorted by alias.
521          * Optimization: Search backwards, assuming that the bindings file is
522          * sorted already.
523          */
524         vector_foreach_slot_backwards(bindings, bdg, i) {
525                 if ((cmp = strcmp(bdg->alias, alias)) <= 0)
526                         break;
527         }
528
529         /* Check for exact match */
530         if (i >= 0 && cmp == 0)
531                 return strcmp(bdg->wwid, wwid) ?
532                         BINDING_CONFLICT : BINDING_EXISTS;
533
534         i++;
535         bdg = calloc(1, sizeof(*bdg));
536         if (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;
542                 else
543                         _free_binding(bdg);
544         }
545
546         return BINDING_ERROR;
547 }
548
549 static int write_bindings_file(const Bindings *bindings, int fd)
550 {
551         struct binding *bnd;
552         STRBUF_ON_STACK(line);
553         int i;
554
555         if (write(fd, BINDINGS_FILE_HEADER, sizeof(BINDINGS_FILE_HEADER) - 1)
556             != sizeof(BINDINGS_FILE_HEADER) - 1)
557                 return -1;
558
559         vector_foreach_slot(bindings, bnd, i) {
560                 int len;
561
562                 if ((len = print_strbuf(&line, "%s %s\n",
563                                         bnd->alias, bnd->wwid)) < 0)
564                         return -1;
565                 if (write(fd, get_strbuf_str(&line), len) != len)
566                         return -1;
567                 truncate_strbuf(&line, 0);
568         }
569         return 0;
570 }
571
572 static int fix_bindings_file(const struct config *conf,
573                              const Bindings *bindings)
574 {
575         int rc;
576         long fd;
577         char tempname[PATH_MAX];
578         mode_t old_umask;
579
580         if (safe_sprintf(tempname, "%s.XXXXXX", conf->bindings_file))
581                 return -1;
582         /* coverity: SECURE_TEMP */
583         old_umask = umask(0077);
584         if ((fd = mkstemp(tempname)) == -1) {
585                 condlog(1, "%s: mkstemp: %m", __func__);
586                 return -1;
587         }
588         umask(old_umask);
589         pthread_cleanup_push(close_fd, (void*)fd);
590         rc = write_bindings_file(bindings, fd);
591         pthread_cleanup_pop(1);
592         if (rc == -1) {
593                 condlog(1, "failed to write new bindings file %s",
594                         tempname);
595                 unlink(tempname);
596                 return rc;
597         }
598         if ((rc = rename(tempname, conf->bindings_file)) == -1)
599                 condlog(0, "%s: rename: %m", __func__);
600         else
601                 condlog(1, "updated bindings file %s", conf->bindings_file);
602         return rc;
603 }
604
605 static int _check_bindings_file(const struct config *conf, FILE *file,
606                                  Bindings *bindings)
607 {
608         int rc = 0;
609         unsigned int linenr = 0;
610         char *line = NULL;
611         size_t line_len = 0;
612         ssize_t n;
613
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;
618
619                 linenr++;
620                 c = strpbrk(line, "#\n\r");
621                 if (c)
622                         *c = '\0';
623                 alias = strtok_r(line, " \t", &saveptr);
624                 if (!alias) /* blank line */
625                         continue;
626                 wwid = strtok_r(NULL, " \t", &saveptr);
627                 if (!wwid) {
628                         condlog(1, "invalid line %d in bindings file, missing WWID",
629                                 linenr);
630                         continue;
631                 }
632                 c = strtok_r(NULL, " \t", &saveptr);
633                 if (c)
634                         /* This is non-fatal */
635                         condlog(1, "invalid line %d in bindings file, extra args \"%s\"",
636                                 linenr, c);
637
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);
643                         rc = -1;
644                         continue;
645                 }
646
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);
652                         rc = -1;
653                         break;
654                 case BINDING_EXISTS:
655                         condlog(2, "duplicate line for alias %s in bindings file on line %u",
656                                 alias, linenr);
657                         break;
658                 case BINDING_ERROR:
659                         condlog(2, "error adding binding %s -> %s",
660                                 alias, wwid);
661                         break;
662                 default:
663                         break;
664                 }
665         }
666         pthread_cleanup_pop(1);
667         return rc;
668 }
669
670 static void cleanup_fclose(void *p)
671 {
672         fclose(p);
673 }
674
675 /*
676  * check_alias_settings(): test for inconsistent alias configuration
677  *
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.
687  *
688  * Returns: 0 in case of success, -1 if the configuration was bad
689  * and couldn't be fixed.
690  */
691 int check_alias_settings(const struct config *conf)
692 {
693         int can_write;
694         int rc = 0, i, fd;
695         Bindings bindings = {.allocated = 0, };
696         struct mpentry *mpe;
697
698         pthread_cleanup_push_cast(free_bindings, &bindings);
699         vector_foreach_slot(conf->mptable, mpe, i) {
700                 if (!mpe->wwid || !mpe->alias)
701                         continue;
702                 if (add_binding(&bindings, mpe->alias, mpe->wwid) ==
703                     BINDING_CONFLICT) {
704                         condlog(0, "ERROR: alias \"%s\" bound to multiple wwids in multipath.conf, "
705                                 "discarding binding to %s",
706                                 mpe->alias, mpe->wwid);
707                         free(mpe->alias);
708                         mpe->alias = NULL;
709                 }
710         }
711         /* This clears the bindings */
712         pthread_cleanup_pop(1);
713
714         pthread_cleanup_push_cast(free_bindings, &bindings);
715         fd = open_file(conf->bindings_file, &can_write, BINDINGS_FILE_HEADER);
716         if (fd != -1) {
717                 FILE *file = fdopen(fd, "r");
718
719                 if (file != NULL) {
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);
725                         else if (rc == -1)
726                                 condlog(0, "ERROR: bad settings in read-only bindings file %s",
727                                         conf->bindings_file);
728                 } else {
729                         condlog(1, "failed to fdopen %s: %m",
730                                 conf->bindings_file);
731                         close(fd);
732                 }
733         }
734         pthread_cleanup_pop(1);
735         return rc;
736 }