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