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