multipath: fix issues found by compiling with gcc 10
[multipath-tools/.git] / multipath / main.c
1 /*
2  * Soft:        multipath device mapper target autoconfig
3  *
4  * Version:     $Id: main.h,v 0.0.1 2003/09/18 15:13:38 cvaroqui Exp $
5  *
6  * Author:      Christophe Varoqui
7  *
8  *              This program is distributed in the hope that it will be useful,
9  *              but WITHOUT ANY WARRANTY; without even the implied warranty of
10  *              MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11  *              See the GNU General Public License for more details.
12  *
13  *              This program is free software; you can redistribute it and/or
14  *              modify it under the terms of the GNU General Public License
15  *              as published by the Free Software Foundation; either version
16  *              2 of the License, or (at your option) any later version.
17  *
18  * Copyright (c) 2003, 2004, 2005 Christophe Varoqui
19  * Copyright (c) 2005 Benjamin Marzinski, Redhat
20  * Copyright (c) 2005 Kiyoshi Ueda, NEC
21  * Copyright (c) 2005 Patrick Caulfield, Redhat
22  * Copyright (c) 2005 Edward Goggin, EMC
23  */
24
25 #include <sys/types.h>
26 #include <sys/stat.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <unistd.h>
30 #include <ctype.h>
31 #include <libudev.h>
32 #include <syslog.h>
33 #include <fcntl.h>
34
35 #include "checkers.h"
36 #include "prio.h"
37 #include "vector.h"
38 #include "memory.h"
39 #include <libdevmapper.h>
40 #include "devmapper.h"
41 #include "util.h"
42 #include "defaults.h"
43 #include "config.h"
44 #include "structs.h"
45 #include "structs_vec.h"
46 #include "dmparser.h"
47 #include "sysfs.h"
48 #include "blacklist.h"
49 #include "discovery.h"
50 #include "debug.h"
51 #include "switchgroup.h"
52 #include "dm-generic.h"
53 #include "print.h"
54 #include "alias.h"
55 #include "configure.h"
56 #include "pgpolicies.h"
57 #include "version.h"
58 #include <errno.h>
59 #include "wwids.h"
60 #include "uxsock.h"
61 #include "mpath_cmd.h"
62 #include "foreign.h"
63 #include "propsel.h"
64 #include "time-util.h"
65 #include "file.h"
66
67 int logsink;
68 struct udev *udev;
69 struct config *multipath_conf;
70
71 /*
72  * Return values of configure(), print_cmd_valid(), and main().
73  * RTVL_{YES,NO} are synonyms for RTVL_{OK,FAIL} for the CMD_VALID_PATH case.
74  */
75 enum {
76         RTVL_OK = 0,
77         RTVL_YES = RTVL_OK,
78         RTVL_FAIL = 1,
79         RTVL_NO = RTVL_FAIL,
80         RTVL_MAYBE, /* only used internally, never returned */
81         RTVL_RETRY, /* returned by configure(), not by main() */
82 };
83
84 struct config *get_multipath_config(void)
85 {
86         return multipath_conf;
87 }
88
89 void put_multipath_config(__attribute__((unused)) void *arg)
90 {
91         /* Noop for now */
92 }
93
94 static int
95 dump_config (struct config *conf, vector hwes, vector mpvec)
96 {
97         char * reply = snprint_config(conf, NULL, hwes, mpvec);
98
99         if (reply != NULL) {
100                 printf("%s", reply);
101                 FREE(reply);
102                 return 0;
103         } else
104                 return 1;
105 }
106
107 void rcu_register_thread_memb(void) {}
108
109 void rcu_unregister_thread_memb(void) {}
110
111 static int
112 filter_pathvec (vector pathvec, char * refwwid)
113 {
114         int i;
115         struct path * pp;
116
117         if (!refwwid || !strlen(refwwid))
118                 return 0;
119
120         vector_foreach_slot (pathvec, pp, i) {
121                 if (strncmp(pp->wwid, refwwid, WWID_SIZE) != 0) {
122                         condlog(3, "skip path %s : out of scope", pp->dev);
123                         free_path(pp);
124                         vector_del_slot(pathvec, i);
125                         i--;
126                 }
127         }
128         return 0;
129 }
130
131 static void
132 usage (char * progname)
133 {
134         fprintf (stderr, VERSION_STRING);
135         fprintf (stderr, "Usage:\n");
136         fprintf (stderr, "  %s [-v level] [-B|-d|-i|-q|-r] [-b file] [-p policy] [device]\n", progname);
137         fprintf (stderr, "  %s [-v level] [-R retries] -f device\n", progname);
138         fprintf (stderr, "  %s [-v level] [-R retries] -F\n", progname);
139         fprintf (stderr, "  %s [-v level] [-l|-ll] [device]\n", progname);
140         fprintf (stderr, "  %s [-v level] [-a|-w] device\n", progname);
141         fprintf (stderr, "  %s [-v level] -W\n", progname);
142         fprintf (stderr, "  %s [-v level] [-i] [-c|-C] device\n", progname);
143         fprintf (stderr, "  %s [-v level] [-i] [-u|-U]\n", progname);
144         fprintf (stderr, "  %s [-h|-t|-T]\n", progname);
145         fprintf (stderr,
146                 "\n"
147                 "Where:\n"
148                 "  -h      print this usage text\n"
149                 "  -l      show multipath topology (sysfs and DM info)\n"
150                 "  -ll     show multipath topology (maximum info)\n"
151                 "  -f      flush a multipath device map\n"
152                 "  -F      flush all multipath device maps\n"
153                 "  -a      add a device wwid to the wwids file\n"
154                 "  -c      check if a device should be a path in a multipath device\n"
155                 "  -C      check if a multipath device has usable paths\n"
156                 "  -q      allow queue_if_no_path when multipathd is not running\n"
157                 "  -d      dry run, do not create or update devmaps\n"
158                 "  -t      display the currently used multipathd configuration\n"
159                 "  -T      display the multipathd configuration without builtin defaults\n"
160                 "  -r      force devmap reload\n"
161                 "  -i      ignore wwids file\n"
162                 "  -B      treat the bindings file as read only\n"
163                 "  -b fil  bindings file location\n"
164                 "  -w      remove a device from the wwids file\n"
165                 "  -W      reset the wwids file include only the current devices\n"
166                 "  -R num  number of times to retry removes of in-use devices\n"
167                 "  -u      check if the device specified in the program environment should be a\n"
168                 "          path in a multipath device\n"
169                 "  -U      check if the device specified in the program environment is a\n"
170                 "          multipath device with usable paths, see -C flag\n"
171                 "  -p pol  force all maps to specified path grouping policy:\n"
172                 "          . failover            one path per priority group\n"
173                 "          . multibus            all paths in one priority group\n"
174                 "          . group_by_serial     one priority group per serial\n"
175                 "          . group_by_prio       one priority group per priority lvl\n"
176                 "          . group_by_node_name  one priority group per target node\n"
177                 "  -v lvl  verbosity level:\n"
178                 "          . 0 no output\n"
179                 "          . 1 print created devmap names only\n"
180                 "          . 2 default verbosity\n"
181                 "          . 3 print debug information\n"
182                 "  device  action limited to:\n"
183                 "          . multipath named 'device' (ex: mpath0)\n"
184                 "          . multipath whose wwid is 'device' (ex: 60051...)\n"
185                 "          . multipath including the path named 'device' (ex: /dev/sda or\n"
186                 "            /dev/dm-0)\n"
187                 "          . multipath including the path with maj:min 'device' (ex: 8:0)\n"
188                 );
189
190 }
191
192 static int
193 update_paths (struct multipath * mpp, int quick)
194 {
195         int i, j;
196         struct pathgroup * pgp;
197         struct path * pp;
198         struct config *conf;
199
200         if (!mpp->pg)
201                 return 0;
202
203         vector_foreach_slot (mpp->pg, pgp, i) {
204                 if (!pgp->paths)
205                         continue;
206
207                 vector_foreach_slot (pgp->paths, pp, j) {
208                         if (!strlen(pp->dev)) {
209                                 if (devt2devname(pp->dev, FILE_NAME_SIZE,
210                                                  pp->dev_t)) {
211                                         /*
212                                          * path is not in sysfs anymore
213                                          */
214                                         pp->chkrstate = pp->state = PATH_DOWN;
215                                         pp->offline = 1;
216                                         continue;
217                                 }
218                                 pp->mpp = mpp;
219                                 if (quick)
220                                         continue;
221                                 conf = get_multipath_config();
222                                 if (pathinfo(pp, conf, DI_ALL))
223                                         pp->state = PATH_UNCHECKED;
224                                 put_multipath_config(conf);
225                                 continue;
226                         }
227                         pp->mpp = mpp;
228                         if (quick)
229                                 continue;
230                         if (pp->state == PATH_UNCHECKED ||
231                             pp->state == PATH_WILD) {
232                                 conf = get_multipath_config();
233                                 if (pathinfo(pp, conf, DI_CHECKER))
234                                         pp->state = PATH_UNCHECKED;
235                                 put_multipath_config(conf);
236                         }
237
238                         if (pp->priority == PRIO_UNDEF) {
239                                 conf = get_multipath_config();
240                                 if (pathinfo(pp, conf, DI_PRIO))
241                                         pp->priority = PRIO_UNDEF;
242                                 put_multipath_config(conf);
243                         }
244                 }
245         }
246         return 0;
247 }
248
249 static int
250 get_dm_mpvec (enum mpath_cmds cmd, vector curmp, vector pathvec, char * refwwid)
251 {
252         int i;
253         struct multipath * mpp;
254         char params[PARAMS_SIZE], status[PARAMS_SIZE];
255
256         if (dm_get_maps(curmp))
257                 return 1;
258
259         vector_foreach_slot (curmp, mpp, i) {
260                 /*
261                  * discard out of scope maps
262                  */
263                 if (refwwid && strlen(refwwid) &&
264                     strncmp(mpp->wwid, refwwid, WWID_SIZE)) {
265                         condlog(3, "skip map %s: out of scope", mpp->alias);
266                         free_multipath(mpp, KEEP_PATHS);
267                         vector_del_slot(curmp, i);
268                         i--;
269                         continue;
270                 }
271
272                 if (cmd == CMD_VALID_PATH)
273                         continue;
274
275                 dm_get_map(mpp->alias, &mpp->size, params);
276                 condlog(3, "params = %s", params);
277                 dm_get_status(mpp->alias, status);
278                 condlog(3, "status = %s", status);
279
280                 disassemble_map(pathvec, params, mpp, 0);
281
282                 /*
283                  * disassemble_map() can add new paths to pathvec.
284                  * If not in "fast list mode", we need to fetch information
285                  * about them
286                  */
287                 update_paths(mpp, (cmd == CMD_LIST_SHORT));
288
289                 if (cmd == CMD_LIST_LONG)
290                         mpp->bestpg = select_path_group(mpp);
291
292                 disassemble_status(status, mpp);
293
294                 if (cmd == CMD_LIST_SHORT ||
295                     cmd == CMD_LIST_LONG) {
296                         struct config *conf = get_multipath_config();
297                         print_multipath_topology(mpp, conf->verbosity);
298                         put_multipath_config(conf);
299                 }
300
301                 if (cmd == CMD_CREATE)
302                         reinstate_paths(mpp);
303         }
304
305         if (cmd == CMD_LIST_SHORT || cmd == CMD_LIST_LONG) {
306                 struct config *conf = get_multipath_config();
307
308                 print_foreign_topology(conf->verbosity);
309                 put_multipath_config(conf);
310         }
311
312         return 0;
313 }
314
315 static int check_usable_paths(struct config *conf,
316                               const char *devpath, enum devtypes dev_type)
317 {
318         struct udev_device *ud = NULL;
319         struct multipath *mpp = NULL;
320         struct pathgroup *pg;
321         struct path *pp;
322         char *mapname;
323         vector pathvec = NULL;
324         char params[PARAMS_SIZE], status[PARAMS_SIZE];
325         dev_t devt;
326         int r = 1, i, j;
327
328         ud = get_udev_device(devpath, dev_type);
329         if (ud == NULL)
330                 return r;
331
332         devt = udev_device_get_devnum(ud);
333         if (!dm_is_dm_major(major(devt))) {
334                 condlog(1, "%s is not a dm device", devpath);
335                 goto out;
336         }
337
338         mapname = dm_mapname(major(devt), minor(devt));
339         if (mapname == NULL) {
340                 condlog(1, "dm device not found: %s", devpath);
341                 goto out;
342         }
343
344         if (dm_is_mpath(mapname) != 1) {
345                 condlog(1, "%s is not a multipath map", devpath);
346                 goto free;
347         }
348
349         /* pathvec is needed for disassemble_map */
350         pathvec = vector_alloc();
351         if (pathvec == NULL)
352                 goto free;
353
354         mpp = dm_get_multipath(mapname);
355         if (mpp == NULL)
356                 goto free;
357
358         dm_get_map(mpp->alias, &mpp->size, params);
359         dm_get_status(mpp->alias, status);
360         disassemble_map(pathvec, params, mpp, 0);
361         disassemble_status(status, mpp);
362
363         vector_foreach_slot (mpp->pg, pg, i) {
364                 vector_foreach_slot (pg->paths, pp, j) {
365                         pp->udev = get_udev_device(pp->dev_t, DEV_DEVT);
366                         if (pp->udev == NULL)
367                                 continue;
368                         if (pathinfo(pp, conf, DI_SYSFS|DI_NOIO|DI_CHECKER) != PATHINFO_OK)
369                                 continue;
370
371                         if (pp->state == PATH_UP &&
372                             pp->dmstate == PSTATE_ACTIVE) {
373                                 condlog(3, "%s: path %s is usable",
374                                         devpath, pp->dev);
375                                 r = 0;
376                                 goto found;
377                         }
378                 }
379         }
380 found:
381         condlog(r == 0 ? 3 : 2, "%s:%s usable paths found",
382                 devpath, r == 0 ? "" : " no");
383 free:
384         FREE(mapname);
385         free_multipath(mpp, FREE_PATHS);
386         vector_free(pathvec);
387 out:
388         udev_device_unref(ud);
389         return r;
390 }
391
392 enum {
393         FIND_MULTIPATHS_WAIT_DONE = 0,
394         FIND_MULTIPATHS_WAITING = 1,
395         FIND_MULTIPATHS_ERROR = -1,
396         FIND_MULTIPATHS_NEVER = -2,
397 };
398
399 static const char shm_find_mp_dir[] = MULTIPATH_SHM_BASE "find_multipaths";
400
401 /**
402  * find_multipaths_check_timeout(wwid, tmo)
403  * Helper for "find_multipaths smart"
404  *
405  * @param[in] pp: path to check / record
406  * @param[in] tmo: configured timeout for this WWID, or value <= 0 for checking
407  * @param[out] until: timestamp until we must wait, CLOCK_REALTIME, if return
408  *             value is FIND_MULTIPATHS_WAITING
409  * @returns: FIND_MULTIPATHS_WAIT_DONE, if waiting has finished
410  * @returns: FIND_MULTIPATHS_ERROR, if internal error occurred
411  * @returns: FIND_MULTIPATHS_NEVER, if tmo is 0 and we didn't wait for this
412  *           device
413  * @returns: FIND_MULTIPATHS_WAITING, if timeout hasn't expired
414  */
415 static int find_multipaths_check_timeout(const struct path *pp, long tmo,
416                                          struct timespec *until)
417 {
418         char path[PATH_MAX];
419         struct timespec now, ftimes[2], tdiff;
420         struct stat st;
421         long fd;
422         int r, retries = 0;
423
424         clock_gettime(CLOCK_REALTIME, &now);
425
426         if (safe_sprintf(path, "%s/%s", shm_find_mp_dir, pp->dev_t)) {
427                 condlog(1, "%s: path name overflow", __func__);
428                 return FIND_MULTIPATHS_ERROR;
429         }
430
431         if (ensure_directories_exist(path, 0700)) {
432                 condlog(1, "%s: error creating directories", __func__);
433                 return FIND_MULTIPATHS_ERROR;
434         }
435
436 retry:
437         fd = open(path, O_RDONLY);
438         if (fd != -1) {
439                 pthread_cleanup_push(close_fd, (void *)fd);
440                 r = fstat(fd, &st);
441                 pthread_cleanup_pop(1);
442
443         } else if (tmo > 0) {
444                 if (errno == ENOENT)
445                         fd = open(path, O_RDWR|O_EXCL|O_CREAT, 0644);
446                 if (fd == -1) {
447                         if (errno == EEXIST && !retries++)
448                                 /* We could have raced with another process */
449                                 goto retry;
450                         condlog(1, "%s: error opening %s: %s",
451                                 __func__, path, strerror(errno));
452                         return FIND_MULTIPATHS_ERROR;
453                 };
454
455                 pthread_cleanup_push(close_fd, (void *)fd);
456                 /*
457                  * We just created the file. Set st_mtim to our desired
458                  * expiry time.
459                  */
460                 ftimes[0].tv_sec = 0;
461                 ftimes[0].tv_nsec = UTIME_OMIT;
462                 ftimes[1].tv_sec = now.tv_sec + tmo;
463                 ftimes[1].tv_nsec = now.tv_nsec;
464                 if (futimens(fd, ftimes) != 0) {
465                         condlog(1, "%s: error in futimens(%s): %s", __func__,
466                                 path, strerror(errno));
467                 }
468                 r = fstat(fd, &st);
469                 pthread_cleanup_pop(1);
470         } else
471                 return FIND_MULTIPATHS_NEVER;
472
473         if (r != 0) {
474                 condlog(1, "%s: error in fstat for %s: %m", __func__, path);
475                 return FIND_MULTIPATHS_ERROR;
476         }
477
478         timespecsub(&st.st_mtim, &now, &tdiff);
479
480         if (tdiff.tv_sec <= 0)
481                 return FIND_MULTIPATHS_WAIT_DONE;
482
483         *until = tdiff;
484         return FIND_MULTIPATHS_WAITING;
485 }
486
487 static int print_cmd_valid(int k, const vector pathvec,
488                            struct config *conf)
489 {
490         int wait = FIND_MULTIPATHS_NEVER;
491         struct timespec until;
492         struct path *pp;
493
494         if (k != RTVL_YES && k != RTVL_NO && k != RTVL_MAYBE)
495                 return RTVL_NO;
496
497         if (k == RTVL_MAYBE) {
498                 /*
499                  * Caller ensures that pathvec[0] is the path to
500                  * examine.
501                  */
502                 pp = VECTOR_SLOT(pathvec, 0);
503                 select_find_multipaths_timeout(conf, pp);
504                 wait = find_multipaths_check_timeout(
505                         pp, pp->find_multipaths_timeout, &until);
506                 if (wait != FIND_MULTIPATHS_WAITING)
507                         k = RTVL_NO;
508         } else if (pathvec != NULL && (pp = VECTOR_SLOT(pathvec, 0)))
509                 wait = find_multipaths_check_timeout(pp, 0, &until);
510         if (wait == FIND_MULTIPATHS_WAITING)
511                 printf("FIND_MULTIPATHS_WAIT_UNTIL=\"%ld.%06ld\"\n",
512                                until.tv_sec, until.tv_nsec/1000);
513         else if (wait == FIND_MULTIPATHS_WAIT_DONE)
514                 printf("FIND_MULTIPATHS_WAIT_UNTIL=\"0\"\n");
515         printf("DM_MULTIPATH_DEVICE_PATH=\"%d\"\n",
516                k == RTVL_MAYBE ? 2 : k == RTVL_YES ? 1 : 0);
517         /* Never return RTVL_MAYBE */
518         return k == RTVL_NO ? RTVL_NO : RTVL_YES;
519 }
520
521 /*
522  * Returns true if this device has been handled before,
523  * and released to systemd.
524  *
525  * This must be called before get_refwwid(),
526  * otherwise udev_device_new_from_environment() will have
527  * destroyed environ(7).
528  */
529 static bool released_to_systemd(void)
530 {
531         static const char dmdp[] = "DM_MULTIPATH_DEVICE_PATH";
532         const char *dm_mp_dev_path = getenv(dmdp);
533         bool ret;
534
535         ret = dm_mp_dev_path != NULL && !strcmp(dm_mp_dev_path, "0");
536         condlog(4, "%s: %s=%s -> %d", __func__, dmdp, dm_mp_dev_path, ret);
537         return ret;
538 }
539
540 static int
541 configure (struct config *conf, enum mpath_cmds cmd,
542            enum devtypes dev_type, char *devpath)
543 {
544         vector curmp = NULL;
545         vector pathvec = NULL;
546         struct vectors vecs;
547         int r = RTVL_FAIL, rc;
548         int di_flag = 0;
549         char * refwwid = NULL;
550         char * dev = NULL;
551         bool released = released_to_systemd();
552
553         /*
554          * allocate core vectors to store paths and multipaths
555          */
556         curmp = vector_alloc();
557         pathvec = vector_alloc();
558
559         if (!curmp || !pathvec) {
560                 condlog(0, "can not allocate memory");
561                 goto out;
562         }
563         vecs.pathvec = pathvec;
564         vecs.mpvec = curmp;
565
566         dev = convert_dev(devpath, (dev_type == DEV_DEVNODE));
567
568         /*
569          * if we have a blacklisted device parameter, exit early
570          */
571         if (dev && (dev_type == DEV_DEVNODE ||
572                     dev_type == DEV_UEVENT) &&
573             cmd != CMD_REMOVE_WWID &&
574             (filter_devnode(conf->blist_devnode,
575                             conf->elist_devnode, dev) > 0)) {
576                 goto print_valid;
577         }
578
579         /*
580          * scope limiting must be translated into a wwid
581          * failing the translation is fatal (by policy)
582          */
583         if (devpath) {
584                 int failed = get_refwwid(cmd, devpath, dev_type,
585                                          pathvec, &refwwid);
586                 if (!refwwid) {
587                         condlog(4, "%s: failed to get wwid", devpath);
588                         if (failed == 2 && cmd == CMD_VALID_PATH)
589                                 goto print_valid;
590                         else
591                                 condlog(3, "scope is null");
592                         goto out;
593                 }
594                 if (cmd == CMD_REMOVE_WWID) {
595                         rc = remove_wwid(refwwid);
596                         if (rc == 0) {
597                                 printf("wwid '%s' removed\n", refwwid);
598                                 r = RTVL_OK;
599                         } else if (rc == 1) {
600                                 printf("wwid '%s' not in wwids file\n",
601                                         refwwid);
602                                 r = RTVL_OK;
603                         }
604                         goto out;
605                 }
606                 if (cmd == CMD_ADD_WWID) {
607                         rc = remember_wwid(refwwid);
608                         if (rc >= 0) {
609                                 printf("wwid '%s' added\n", refwwid);
610                                 r = RTVL_OK;
611                         } else
612                                 printf("failed adding '%s' to wwids file\n",
613                                        refwwid);
614                         goto out;
615                 }
616                 condlog(3, "scope limited to %s", refwwid);
617                 /* If you are ignoring the wwids file and find_multipaths is
618                  * set, you need to actually check if there are two available
619                  * paths to determine if this path should be multipathed. To
620                  * do this, we put off the check until after discovering all
621                  * the paths.
622                  * Paths listed in the wwids file are always considered valid.
623                  */
624                 if (cmd == CMD_VALID_PATH) {
625                         if (is_failed_wwid(refwwid) == WWID_IS_FAILED) {
626                                 r = RTVL_NO;
627                                 goto print_valid;
628                         }
629                         if ((!find_multipaths_on(conf) &&
630                                     ignore_wwids_on(conf)) ||
631                                    check_wwids_file(refwwid, 0) == 0)
632                                 r = RTVL_YES;
633                         if (!ignore_wwids_on(conf))
634                                 goto print_valid;
635                         /* At this point, either r==0 or find_multipaths_on. */
636
637                         /*
638                          * Shortcut for find_multipaths smart:
639                          * Quick check if path is already multipathed.
640                          */
641                         if (sysfs_is_multipathed(VECTOR_SLOT(pathvec, 0))) {
642                                 r = RTVL_YES;
643                                 goto print_valid;
644                         }
645
646                         /*
647                          * DM_MULTIPATH_DEVICE_PATH=="0" means that we have
648                          * been called for this device already, and have
649                          * released it to systemd. Unless the device is now
650                          * already multipathed (see above), we can't try to
651                          * grab it, because setting SYSTEMD_READY=0 would
652                          * cause file systems to be unmounted.
653                          * Leave DM_MULTIPATH_DEVICE_PATH="0".
654                          */
655                         if (released) {
656                                 r = RTVL_NO;
657                                 goto print_valid;
658                         }
659                         if (r == RTVL_YES)
660                                 goto print_valid;
661                         /* find_multipaths_on: Fall through to path detection */
662                 }
663         }
664
665         /*
666          * get a path list
667          */
668         if (devpath)
669                 di_flag = DI_WWID;
670
671         if (cmd == CMD_LIST_LONG)
672                 /* extended path info '-ll' */
673                 di_flag |= DI_SYSFS | DI_CHECKER | DI_SERIAL;
674         else if (cmd == CMD_LIST_SHORT)
675                 /* minimum path info '-l' */
676                 di_flag |= DI_SYSFS;
677         else
678                 /* maximum info */
679                 di_flag = DI_ALL;
680
681         if (path_discovery(pathvec, di_flag) < 0)
682                 goto out;
683
684         if (conf->verbosity > 2)
685                 print_all_paths(pathvec, 1);
686
687         get_path_layout(pathvec, 0);
688         foreign_path_layout();
689
690         if (get_dm_mpvec(cmd, curmp, pathvec, refwwid))
691                 goto out;
692
693         filter_pathvec(pathvec, refwwid);
694
695         if (cmd == CMD_DUMP_CONFIG) {
696                 vector hwes = get_used_hwes(pathvec);
697
698                 dump_config(conf, hwes, curmp);
699                 vector_free(hwes);
700                 goto out;
701         }
702
703         if (cmd == CMD_VALID_PATH) {
704                 struct path *pp;
705                 int fd;
706
707                 /* This only happens if find_multipaths and
708                  * ignore_wwids is set, and the path is not in WWIDs
709                  * file, not currently multipathed, and has
710                  * never been released to systemd.
711                  * If there is currently a multipath device matching
712                  * the refwwid, or there is more than one path matching
713                  * the refwwid, then the path is valid */
714                 if (VECTOR_SIZE(curmp) != 0) {
715                         r = RTVL_YES;
716                         goto print_valid;
717                 } else if (VECTOR_SIZE(pathvec) > 1)
718                         r = RTVL_YES;
719                 else
720                         r = RTVL_MAYBE;
721
722                 /*
723                  * If opening the path with O_EXCL fails, the path
724                  * is in use (e.g. mounted during initramfs processing).
725                  * We know that it's not used by dm-multipath.
726                  * We may not set SYSTEMD_READY=0 on such devices, it
727                  * might cause systemd to umount the device.
728                  * Use O_RDONLY, because udevd would trigger another
729                  * uevent for close-after-write.
730                  *
731                  * The O_EXCL check is potentially dangerous, because it may
732                  * race with other tasks trying to access the device. Therefore
733                  * this code is only executed if the path hasn't been released
734                  * to systemd earlier (see above).
735                  *
736                  * get_refwwid() above stores the path we examine in slot 0.
737                  */
738                 pp = VECTOR_SLOT(pathvec, 0);
739                 fd = open(udev_device_get_devnode(pp->udev),
740                           O_RDONLY|O_EXCL);
741                 if (fd >= 0)
742                         close(fd);
743                 else {
744                         condlog(3, "%s: path %s is in use: %s",
745                                 __func__, pp->dev,
746                                 strerror(errno));
747                         /*
748                          * Check if we raced with multipathd
749                          */
750                         r = sysfs_is_multipathed(VECTOR_SLOT(pathvec, 0)) ?
751                                 RTVL_YES : RTVL_NO;
752                 }
753                 goto print_valid;
754         }
755
756         if (cmd != CMD_CREATE && cmd != CMD_DRY_RUN) {
757                 r = RTVL_OK;
758                 goto out;
759         }
760
761         /*
762          * core logic entry point
763          */
764         rc = coalesce_paths(&vecs, NULL, refwwid,
765                            conf->force_reload, cmd);
766         r = rc == CP_RETRY ? RTVL_RETRY : rc == CP_OK ? RTVL_OK : RTVL_FAIL;
767
768 print_valid:
769         if (cmd == CMD_VALID_PATH)
770                 r = print_cmd_valid(r, pathvec, conf);
771
772 out:
773         if (refwwid)
774                 FREE(refwwid);
775
776         free_multipathvec(curmp, KEEP_PATHS);
777         free_pathvec(pathvec, FREE_PATHS);
778
779         return r;
780 }
781
782 static int
783 get_dev_type(char *dev) {
784         struct stat buf;
785         int i;
786
787         if (stat(dev, &buf) == 0 && S_ISBLK(buf.st_mode)) {
788                 if (dm_is_dm_major(major(buf.st_rdev)))
789                         return DEV_DEVMAP;
790                 return DEV_DEVNODE;
791         }
792         else if (sscanf(dev, "%d:%d", &i, &i) == 2)
793                 return DEV_DEVT;
794         else if (valid_alias(dev))
795                 return DEV_DEVMAP;
796         return DEV_NONE;
797 }
798
799 /*
800  * Some multipath commands are dangerous to run while multipathd is running.
801  * For example, "multipath -r" may apply a modified configuration to the kernel,
802  * while multipathd is still using the old configuration, leading to
803  * inconsistent state.
804  *
805  * It is safer to use equivalent multipathd client commands instead.
806  */
807 enum {
808         DELEGATE_OK = 0,
809         DELEGATE_ERROR = -1,
810         NOT_DELEGATED = 1,
811 };
812
813 int delegate_to_multipathd(enum mpath_cmds cmd,
814                            __attribute__((unused)) const char *dev,
815                            __attribute__((unused)) enum devtypes dev_type,
816                            const struct config *conf)
817 {
818         int fd;
819         char command[1024], *p, *reply = NULL;
820         int n, r = DELEGATE_ERROR;
821
822         p = command;
823         *p = '\0';
824         n = sizeof(command);
825
826         if (cmd == CMD_CREATE && conf->force_reload == FORCE_RELOAD_YES) {
827                 p += snprintf(p, n, "reconfigure");
828         }
829         /* Add other translations here */
830
831         if (strlen(command) == 0)
832                 /* No command found, no need to delegate */
833                 return NOT_DELEGATED;
834
835         fd = mpath_connect();
836         if (fd == -1)
837                 return NOT_DELEGATED;
838
839         if (p >= command + sizeof(command)) {
840                 condlog(0, "internal error - command buffer overflow");
841                 goto out;
842         }
843
844         condlog(3, "delegating command to multipathd");
845
846         if (mpath_process_cmd(fd, command, &reply, conf->uxsock_timeout)
847             == -1) {
848                 condlog(1, "error in multipath command %s: %s",
849                         command, strerror(errno));
850                 goto out;
851         }
852
853         if (reply != NULL && *reply != '\0' && strcmp(reply, "ok\n"))
854                 printf("%s", reply);
855         r = DELEGATE_OK;
856
857 out:
858         FREE(reply);
859         close(fd);
860         return r;
861 }
862
863 static int test_multipathd_socket(void)
864 {
865         int fd;
866         /*
867          * "multipath -u" may be run before the daemon is started. In this
868          * case, systemd might own the socket but might delay multipathd
869          * startup until some other unit (udev settle!)  has finished
870          * starting. With many LUNs, the listen backlog may be exceeded, which
871          * would cause connect() to block. This causes udev workers calling
872          * "multipath -u" to hang, and thus creates a deadlock, until "udev
873          * settle" times out.  To avoid this, call connect() in non-blocking
874          * mode here, and take EAGAIN as indication for a filled-up systemd
875          * backlog.
876          */
877
878         fd = __mpath_connect(1);
879         if (fd == -1) {
880                 if (errno == EAGAIN)
881                         condlog(3, "daemon backlog exceeded");
882                 else
883                         return 0;
884         } else
885                 close(fd);
886         return 1;
887 }
888
889 int
890 main (int argc, char *argv[])
891 {
892         int arg;
893         extern char *optarg;
894         extern int optind;
895         int r = RTVL_FAIL;
896         enum mpath_cmds cmd = CMD_CREATE;
897         enum devtypes dev_type = DEV_NONE;
898         char *dev = NULL;
899         struct config *conf;
900         int retries = -1;
901
902         udev = udev_new();
903         logsink = 0;
904         conf = load_config(DEFAULT_CONFIGFILE);
905         if (!conf)
906                 exit(RTVL_FAIL);
907         multipath_conf = conf;
908         conf->retrigger_tries = 0;
909         conf->force_sync = 1;
910         while ((arg = getopt(argc, argv, ":adcChl::FfM:v:p:b:BrR:itTquUwW")) != EOF ) {
911                 switch(arg) {
912                 case 1: printf("optarg : %s\n",optarg);
913                         break;
914                 case 'v':
915                         if (sizeof(optarg) > sizeof(char *) ||
916                             !isdigit(optarg[0])) {
917                                 usage (argv[0]);
918                                 exit(RTVL_FAIL);
919                         }
920
921                         conf->verbosity = atoi(optarg);
922                         break;
923                 case 'b':
924                         conf->bindings_file = strdup(optarg);
925                         break;
926                 case 'B':
927                         conf->bindings_read_only = 1;
928                         break;
929                 case 'q':
930                         conf->allow_queueing = 1;
931                         break;
932                 case 'c':
933                         cmd = CMD_VALID_PATH;
934                         break;
935                 case 'C':
936                         cmd = CMD_USABLE_PATHS;
937                         break;
938                 case 'd':
939                         if (cmd == CMD_CREATE)
940                                 cmd = CMD_DRY_RUN;
941                         break;
942                 case 'f':
943                         conf->remove = FLUSH_ONE;
944                         break;
945                 case 'F':
946                         conf->remove = FLUSH_ALL;
947                         break;
948                 case 'l':
949                         if (optarg && !strncmp(optarg, "l", 1))
950                                 cmd = CMD_LIST_LONG;
951                         else
952                                 cmd = CMD_LIST_SHORT;
953
954                         break;
955                 case 'M':
956 #if _DEBUG_
957                         debug = atoi(optarg);
958 #endif
959                         break;
960                 case 'p':
961                         conf->pgpolicy_flag = get_pgpolicy_id(optarg);
962                         if (conf->pgpolicy_flag == IOPOLICY_UNDEF) {
963                                 printf("'%s' is not a valid policy\n", optarg);
964                                 usage(argv[0]);
965                                 exit(RTVL_FAIL);
966                         }
967                         break;
968                 case 'r':
969                         conf->force_reload = FORCE_RELOAD_YES;
970                         break;
971                 case 'i':
972                         conf->find_multipaths |= _FIND_MULTIPATHS_I;
973                         break;
974                 case 't':
975                         r = dump_config(conf, NULL, NULL) ? RTVL_FAIL : RTVL_OK;
976                         goto out_free_config;
977                 case 'T':
978                         cmd = CMD_DUMP_CONFIG;
979                         break;
980                 case 'h':
981                         usage(argv[0]);
982                         exit(RTVL_OK);
983                 case 'u':
984                         cmd = CMD_VALID_PATH;
985                         dev_type = DEV_UEVENT;
986                         break;
987                 case 'U':
988                         cmd = CMD_USABLE_PATHS;
989                         dev_type = DEV_UEVENT;
990                         break;
991                 case 'w':
992                         cmd = CMD_REMOVE_WWID;
993                         break;
994                 case 'W':
995                         cmd = CMD_RESET_WWIDS;
996                         break;
997                 case 'a':
998                         cmd = CMD_ADD_WWID;
999                         break;
1000                 case 'R':
1001                         retries = atoi(optarg);
1002                         break;
1003                 case ':':
1004                         fprintf(stderr, "Missing option argument\n");
1005                         usage(argv[0]);
1006                         exit(RTVL_FAIL);
1007                 case '?':
1008                         fprintf(stderr, "Unknown switch: %s\n", optarg);
1009                         usage(argv[0]);
1010                         exit(RTVL_FAIL);
1011                 default:
1012                         usage(argv[0]);
1013                         exit(RTVL_FAIL);
1014                 }
1015         }
1016
1017         if (getuid() != 0) {
1018                 fprintf(stderr, "need to be root\n");
1019                 exit(RTVL_FAIL);
1020         }
1021
1022         if (optind < argc) {
1023                 dev = MALLOC(FILE_NAME_SIZE);
1024
1025                 if (!dev)
1026                         goto out;
1027
1028                 strlcpy(dev, argv[optind], FILE_NAME_SIZE);
1029                 if (dev_type != DEV_UEVENT)
1030                         dev_type = get_dev_type(dev);
1031                 if (dev_type == DEV_NONE) {
1032                         condlog(0, "'%s' is not a valid argument\n", dev);
1033                         goto out;
1034                 }
1035         }
1036         if (dev_type == DEV_UEVENT) {
1037                 openlog("multipath", 0, LOG_DAEMON);
1038                 setlogmask(LOG_UPTO(conf->verbosity + 3));
1039                 logsink = 1;
1040         }
1041
1042         set_max_fds(conf->max_fds);
1043
1044         libmp_udev_set_sync_support(1);
1045
1046         if (init_checkers(conf->multipath_dir)) {
1047                 condlog(0, "failed to initialize checkers");
1048                 goto out;
1049         }
1050         if (init_prio(conf->multipath_dir)) {
1051                 condlog(0, "failed to initialize prioritizers");
1052                 goto out;
1053         }
1054         /* Failing here is non-fatal */
1055         init_foreign(conf->multipath_dir, conf->enable_foreign);
1056         if (cmd == CMD_USABLE_PATHS) {
1057                 r = check_usable_paths(conf, dev, dev_type) ?
1058                         RTVL_FAIL : RTVL_OK;
1059                 goto out;
1060         }
1061         if (cmd == CMD_VALID_PATH &&
1062             (!dev || dev_type == DEV_DEVMAP)) {
1063                 condlog(0, "the -c option requires a path to check");
1064                 goto out;
1065         }
1066         if (cmd == CMD_VALID_PATH &&
1067             dev_type == DEV_UEVENT) {
1068                 if (!test_multipathd_socket()) {
1069                         condlog(3, "%s: daemon is not running", dev);
1070                         if (!systemd_service_enabled(dev)) {
1071                                 r = print_cmd_valid(RTVL_NO, NULL, conf);
1072                                 goto out;
1073                         }
1074                 }
1075         }
1076
1077         if (cmd == CMD_REMOVE_WWID && !dev) {
1078                 condlog(0, "the -w option requires a device");
1079                 goto out;
1080         }
1081
1082         switch(delegate_to_multipathd(cmd, dev, dev_type, conf)) {
1083         case DELEGATE_OK:
1084                 exit(RTVL_OK);
1085         case DELEGATE_ERROR:
1086                 exit(RTVL_FAIL);
1087         case NOT_DELEGATED:
1088                 break;
1089         }
1090
1091         if (cmd == CMD_RESET_WWIDS) {
1092                 struct multipath * mpp;
1093                 int i;
1094                 vector curmp;
1095
1096                 curmp = vector_alloc();
1097                 if (!curmp) {
1098                         condlog(0, "can't allocate memory for mp list");
1099                         goto out;
1100                 }
1101                 if (dm_get_maps(curmp) == 0)
1102                         r = replace_wwids(curmp) ? RTVL_FAIL : RTVL_OK;
1103                 if (r == RTVL_OK)
1104                         printf("successfully reset wwids\n");
1105                 vector_foreach_slot_backwards(curmp, mpp, i) {
1106                         vector_del_slot(curmp, i);
1107                         free_multipath(mpp, KEEP_PATHS);
1108                 }
1109                 vector_free(curmp);
1110                 goto out;
1111         }
1112         if (retries < 0)
1113                 retries = conf->remove_retries;
1114         if (conf->remove == FLUSH_ONE) {
1115                 if (dev_type == DEV_DEVMAP) {
1116                         r = dm_suspend_and_flush_map(dev, retries) ?
1117                                 RTVL_FAIL : RTVL_OK;
1118                 } else
1119                         condlog(0, "must provide a map name to remove");
1120
1121                 goto out;
1122         }
1123         else if (conf->remove == FLUSH_ALL) {
1124                 r = dm_flush_maps(retries) ? RTVL_FAIL : RTVL_OK;
1125                 goto out;
1126         }
1127         while ((r = configure(conf, cmd, dev_type, dev)) == RTVL_RETRY)
1128                 condlog(3, "restart multipath configuration process");
1129
1130 out:
1131         dm_lib_release();
1132         dm_lib_exit();
1133
1134         cleanup_foreign();
1135         cleanup_prio();
1136         cleanup_checkers();
1137
1138         /*
1139          * multipath -u must exit with status 0, otherwise udev won't
1140          * import its output.
1141          */
1142         if (cmd == CMD_VALID_PATH && dev_type == DEV_UEVENT && r == RTVL_NO)
1143                 r = RTVL_OK;
1144
1145         if (dev_type == DEV_UEVENT)
1146                 closelog();
1147
1148 out_free_config:
1149         /*
1150          * Freeing config must be done after dm_lib_exit(), because
1151          * the logging function (dm_write_log()), which is called there,
1152          * references the config.
1153          */
1154         free_config(conf);
1155         conf = NULL;
1156         udev_unref(udev);
1157         if (dev)
1158                 FREE(dev);
1159 #ifdef _DEBUG_
1160         dbg_free_final(NULL);
1161 #endif
1162         return r;
1163 }