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