multipath: implement "check usable paths" (-C/-U)
[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
33 #include "checkers.h"
34 #include "prio.h"
35 #include "vector.h"
36 #include "memory.h"
37 #include <libdevmapper.h>
38 #include "devmapper.h"
39 #include "util.h"
40 #include "defaults.h"
41 #include "config.h"
42 #include "structs.h"
43 #include "structs_vec.h"
44 #include "dmparser.h"
45 #include "sysfs.h"
46 #include "blacklist.h"
47 #include "discovery.h"
48 #include "debug.h"
49 #include "switchgroup.h"
50 #include "print.h"
51 #include "alias.h"
52 #include "configure.h"
53 #include "pgpolicies.h"
54 #include "version.h"
55 #include <errno.h>
56 #include <sys/time.h>
57 #include <sys/resource.h>
58 #include "wwids.h"
59 #include "uxsock.h"
60 #include "mpath_cmd.h"
61
62 int logsink;
63 struct udev *udev;
64 struct config *multipath_conf;
65
66 struct config *get_multipath_config(void)
67 {
68         return multipath_conf;
69 }
70
71 void put_multipath_config(struct config *conf)
72 {
73         /* Noop for now */
74 }
75
76 void rcu_register_thread_memb(void) {}
77
78 void rcu_unregister_thread_memb(void) {}
79
80 static int
81 filter_pathvec (vector pathvec, char * refwwid)
82 {
83         int i;
84         struct path * pp;
85
86         if (!refwwid || !strlen(refwwid))
87                 return 0;
88
89         vector_foreach_slot (pathvec, pp, i) {
90                 if (strncmp(pp->wwid, refwwid, WWID_SIZE) != 0) {
91                         condlog(3, "skip path %s : out of scope", pp->dev);
92                         free_path(pp);
93                         vector_del_slot(pathvec, i);
94                         i--;
95                 }
96         }
97         return 0;
98 }
99
100 static void
101 usage (char * progname)
102 {
103         fprintf (stderr, VERSION_STRING);
104         fprintf (stderr, "Usage:\n");
105         fprintf (stderr, "  %s [-a|-c|-w|-W] [-d] [-r] [-i] [-v lvl] [-p pol] [-b fil] [-q] [dev]\n", progname);
106         fprintf (stderr, "  %s -l|-ll|-f [-v lvl] [-b fil] [-R num] [dev]\n", progname);
107         fprintf (stderr, "  %s -F [-v lvl] [-R num]\n", progname);
108         fprintf (stderr, "  %s -t\n", progname);
109         fprintf (stderr, "  %s -h\n", progname);
110         fprintf (stderr,
111                 "\n"
112                 "Where:\n"
113                 "  -h      print this usage text\n"
114                 "  -l      show multipath topology (sysfs and DM info)\n"
115                 "  -ll     show multipath topology (maximum info)\n"
116                 "  -f      flush a multipath device map\n"
117                 "  -F      flush all multipath device maps\n"
118                 "  -a      add a device wwid to the wwids file\n"
119                 "  -c      check if a device should be a path in a multipath device\n"
120                 "  -C      check if a multipath device has usable paths\n"
121                 "  -q      allow queue_if_no_path when multipathd is not running\n"
122                 "  -d      dry run, do not create or update devmaps\n"
123                 "  -t      display the currently used multipathd configuration\n"
124                 "  -r      force devmap reload\n"
125                 "  -i      ignore wwids file\n"
126                 "  -B      treat the bindings file as read only\n"
127                 "  -b fil  bindings file location\n"
128                 "  -w      remove a device from the wwids file\n"
129                 "  -W      reset the wwids file include only the current devices\n"
130                 "  -p pol  force all maps to specified path grouping policy :\n"
131                 "          . failover            one path per priority group\n"
132                 "          . multibus            all paths in one priority group\n"
133                 "          . group_by_serial     one priority group per serial\n"
134                 "          . group_by_prio       one priority group per priority lvl\n"
135                 "          . group_by_node_name  one priority group per target node\n"
136                 "  -v lvl  verbosity level\n"
137                 "          . 0 no output\n"
138                 "          . 1 print created devmap names only\n"
139                 "          . 2 default verbosity\n"
140                 "          . 3 print debug information\n"
141                 "  -R num  number of times to retry removes of in-use devices\n"
142                 "  dev     action limited to:\n"
143                 "          . multipath named 'dev' (ex: mpath0) or\n"
144                 "          . multipath whose wwid is 'dev' (ex: 60051..)\n"
145                 "          . multipath including the path named 'dev' (ex: /dev/sda)\n"
146                 "          . multipath including the path with maj:min 'dev' (ex: 8:0)\n"
147                 );
148
149 }
150
151 static int
152 update_paths (struct multipath * mpp)
153 {
154         int i, j;
155         struct pathgroup * pgp;
156         struct path * pp;
157         struct config *conf;
158
159         if (!mpp->pg)
160                 return 0;
161
162         vector_foreach_slot (mpp->pg, pgp, i) {
163                 if (!pgp->paths)
164                         continue;
165
166                 vector_foreach_slot (pgp->paths, pp, j) {
167                         if (!strlen(pp->dev)) {
168                                 if (devt2devname(pp->dev, FILE_NAME_SIZE,
169                                                  pp->dev_t)) {
170                                         /*
171                                          * path is not in sysfs anymore
172                                          */
173                                         pp->chkrstate = pp->state = PATH_DOWN;
174                                         continue;
175                                 }
176                                 pp->mpp = mpp;
177                                 conf = get_multipath_config();
178                                 if (pathinfo(pp, conf, DI_ALL))
179                                         pp->state = PATH_UNCHECKED;
180                                 put_multipath_config(conf);
181                                 continue;
182                         }
183                         pp->mpp = mpp;
184                         if (pp->state == PATH_UNCHECKED ||
185                             pp->state == PATH_WILD) {
186                                 conf = get_multipath_config();
187                                 if (pathinfo(pp, conf, DI_CHECKER))
188                                         pp->state = PATH_UNCHECKED;
189                                 put_multipath_config(conf);
190                         }
191
192                         if (pp->priority == PRIO_UNDEF) {
193                                 conf = get_multipath_config();
194                                 if (pathinfo(pp, conf, DI_PRIO))
195                                         pp->priority = PRIO_UNDEF;
196                                 put_multipath_config(conf);
197                         }
198                 }
199         }
200         return 0;
201 }
202
203 static int
204 get_dm_mpvec (enum mpath_cmds cmd, vector curmp, vector pathvec, char * refwwid)
205 {
206         int i;
207         struct multipath * mpp;
208         char params[PARAMS_SIZE], status[PARAMS_SIZE];
209
210         if (dm_get_maps(curmp))
211                 return 1;
212
213         vector_foreach_slot (curmp, mpp, i) {
214                 /*
215                  * discard out of scope maps
216                  */
217                 if (refwwid && strlen(refwwid) &&
218                     strncmp(mpp->wwid, refwwid, WWID_SIZE)) {
219                         condlog(3, "skip map %s: out of scope", mpp->alias);
220                         free_multipath(mpp, KEEP_PATHS);
221                         vector_del_slot(curmp, i);
222                         i--;
223                         continue;
224                 }
225
226                 if (cmd == CMD_VALID_PATH)
227                         continue;
228
229                 dm_get_map(mpp->alias, &mpp->size, params);
230                 condlog(3, "params = %s", params);
231                 dm_get_status(mpp->alias, status);
232                 condlog(3, "status = %s", status);
233
234                 disassemble_map(pathvec, params, mpp, 0);
235
236                 /*
237                  * disassemble_map() can add new paths to pathvec.
238                  * If not in "fast list mode", we need to fetch information
239                  * about them
240                  */
241                 if (cmd != CMD_LIST_SHORT)
242                         update_paths(mpp);
243
244                 if (cmd == CMD_LIST_LONG)
245                         mpp->bestpg = select_path_group(mpp);
246
247                 disassemble_status(status, mpp);
248
249                 if (cmd == CMD_LIST_SHORT ||
250                     cmd == CMD_LIST_LONG) {
251                         struct config *conf = get_multipath_config();
252                         print_multipath_topology(mpp, conf->verbosity);
253                         put_multipath_config(conf);
254                 }
255
256                 if (cmd == CMD_CREATE)
257                         reinstate_paths(mpp);
258         }
259         return 0;
260 }
261
262 static int check_usable_paths(struct config *conf,
263                               const char *devpath, enum devtypes dev_type)
264 {
265         struct udev_device *ud = NULL;
266         struct multipath *mpp = NULL;
267         struct pathgroup *pg;
268         struct path *pp;
269         char *mapname;
270         vector pathvec = NULL;
271         char params[PARAMS_SIZE], status[PARAMS_SIZE];
272         dev_t devt;
273         int r = 1, i, j;
274
275         ud = get_udev_device(devpath, dev_type);
276         if (ud == NULL)
277                 return r;
278
279         devt = udev_device_get_devnum(ud);
280         if (!dm_is_dm_major(major(devt))) {
281                 condlog(1, "%s is not a dm device", devpath);
282                 goto out;
283         }
284
285         mapname = dm_mapname(major(devt), minor(devt));
286         if (mapname == NULL) {
287                 condlog(1, "dm device not found: %s", devpath);
288                 goto out;
289         }
290
291         if (!dm_is_mpath(mapname)) {
292                 condlog(1, "%s is not a multipath map", devpath);
293                 goto free;
294         }
295
296         /* pathvec is needed for disassemble_map */
297         pathvec = vector_alloc();
298         if (pathvec == NULL)
299                 goto free;
300
301         mpp = dm_get_multipath(mapname);
302         if (mpp == NULL)
303                 goto free;
304
305         dm_get_map(mpp->alias, &mpp->size, params);
306         dm_get_status(mpp->alias, status);
307         disassemble_map(pathvec, params, mpp, 0);
308         disassemble_status(status, mpp);
309
310         vector_foreach_slot (mpp->pg, pg, i) {
311                 vector_foreach_slot (pg->paths, pp, j) {
312                         pp->udev = get_udev_device(pp->dev_t, DEV_DEVT);
313                         if (pp->udev == NULL)
314                                 continue;
315                         if (pathinfo(pp, conf, DI_SYSFS|DI_NOIO) != PATHINFO_OK)
316                                 continue;
317
318                         if (pp->state == PATH_UP &&
319                             pp->dmstate == PSTATE_ACTIVE) {
320                                 condlog(3, "%s: path %s is usable",
321                                         devpath, pp->dev);
322                                 r = 0;
323                                 goto found;
324                         }
325                 }
326         }
327 found:
328         condlog(2, "%s:%s usable paths found", devpath, r == 0 ? "" : " no");
329 free:
330         FREE(mapname);
331         free_multipath(mpp, FREE_PATHS);
332         vector_free(pathvec);
333 out:
334         udev_device_unref(ud);
335         return r;
336 }
337
338 /*
339  * Return value:
340  *  -1: Retry
341  *   0: Success
342  *   1: Failure
343  */
344 static int
345 configure (struct config *conf, enum mpath_cmds cmd,
346            enum devtypes dev_type, char *devpath)
347 {
348         vector curmp = NULL;
349         vector pathvec = NULL;
350         struct vectors vecs;
351         int r = 1;
352         int di_flag = 0;
353         char * refwwid = NULL;
354         char * dev = NULL;
355
356         /*
357          * allocate core vectors to store paths and multipaths
358          */
359         curmp = vector_alloc();
360         pathvec = vector_alloc();
361
362         if (!curmp || !pathvec) {
363                 condlog(0, "can not allocate memory");
364                 goto out;
365         }
366         vecs.pathvec = pathvec;
367         vecs.mpvec = curmp;
368
369         dev = convert_dev(devpath, (dev_type == DEV_DEVNODE));
370
371         /*
372          * if we have a blacklisted device parameter, exit early
373          */
374         if (dev && (dev_type == DEV_DEVNODE ||
375                     dev_type == DEV_UEVENT) &&
376             cmd != CMD_REMOVE_WWID &&
377             (filter_devnode(conf->blist_devnode,
378                             conf->elist_devnode, dev) > 0)) {
379                 if (cmd == CMD_VALID_PATH)
380                         printf("%s is not a valid multipath device path\n",
381                                devpath);
382                 goto out;
383         }
384
385         /*
386          * scope limiting must be translated into a wwid
387          * failing the translation is fatal (by policy)
388          */
389         if (devpath) {
390                 int failed = get_refwwid(cmd, devpath, dev_type,
391                                          pathvec, &refwwid);
392                 if (!refwwid) {
393                         condlog(4, "%s: failed to get wwid", devpath);
394                         if (failed == 2 && cmd == CMD_VALID_PATH)
395                                 printf("%s is not a valid multipath device path\n", devpath);
396                         else
397                                 condlog(3, "scope is null");
398                         goto out;
399                 }
400                 if (cmd == CMD_REMOVE_WWID) {
401                         r = remove_wwid(refwwid);
402                         if (r == 0)
403                                 printf("wwid '%s' removed\n", refwwid);
404                         else if (r == 1) {
405                                 printf("wwid '%s' not in wwids file\n",
406                                         refwwid);
407                                 r = 0;
408                         }
409                         goto out;
410                 }
411                 if (cmd == CMD_ADD_WWID) {
412                         r = remember_wwid(refwwid);
413                         if (r == 0)
414                                 printf("wwid '%s' added\n", refwwid);
415                         else
416                                 printf("failed adding '%s' to wwids file\n",
417                                        refwwid);
418                         goto out;
419                 }
420                 condlog(3, "scope limited to %s", refwwid);
421                 /* If you are ignoring the wwids file and find_multipaths is
422                  * set, you need to actually check if there are two available
423                  * paths to determine if this path should be multipathed. To
424                  * do this, we put off the check until after discovering all
425                  * the paths */
426                 if (cmd == CMD_VALID_PATH &&
427                     (!conf->find_multipaths || !conf->ignore_wwids)) {
428                         if (conf->ignore_wwids ||
429                             check_wwids_file(refwwid, 0) == 0)
430                                 r = 0;
431
432                         printf("%s %s a valid multipath device path\n",
433                                devpath, r == 0 ? "is" : "is not");
434                         goto out;
435                 }
436         }
437
438         /*
439          * get a path list
440          */
441         if (devpath)
442                 di_flag = DI_WWID;
443
444         if (cmd == CMD_LIST_LONG)
445                 /* extended path info '-ll' */
446                 di_flag |= DI_SYSFS | DI_CHECKER | DI_SERIAL;
447         else if (cmd == CMD_LIST_SHORT)
448                 /* minimum path info '-l' */
449                 di_flag |= DI_SYSFS;
450         else
451                 /* maximum info */
452                 di_flag = DI_ALL;
453
454         if (path_discovery(pathvec, di_flag) < 0)
455                 goto out;
456
457         if (conf->verbosity > 2)
458                 print_all_paths(pathvec, 1);
459
460         get_path_layout(pathvec, 0);
461
462         if (get_dm_mpvec(cmd, curmp, pathvec, refwwid))
463                 goto out;
464
465         filter_pathvec(pathvec, refwwid);
466
467
468         if (cmd == CMD_VALID_PATH) {
469                 /* This only happens if find_multipaths and
470                  * ignore_wwids is set.
471                  * If there is currently a multipath device matching
472                  * the refwwid, or there is more than one path matching
473                  * the refwwid, then the path is valid */
474                 if (VECTOR_SIZE(curmp) != 0 || VECTOR_SIZE(pathvec) > 1)
475                         r = 0;
476                 printf("%s %s a valid multipath device path\n",
477                        devpath, r == 0 ? "is" : "is not");
478                 goto out;
479         }
480
481         if (cmd != CMD_CREATE && cmd != CMD_DRY_RUN) {
482                 r = 0;
483                 goto out;
484         }
485
486         /*
487          * core logic entry point
488          */
489         r = coalesce_paths(&vecs, NULL, refwwid,
490                            conf->force_reload, cmd);
491
492 out:
493         if (refwwid)
494                 FREE(refwwid);
495
496         free_multipathvec(curmp, KEEP_PATHS);
497         free_pathvec(pathvec, FREE_PATHS);
498
499         return r;
500 }
501
502 static int
503 dump_config (struct config *conf)
504 {
505         char * c, * tmp = NULL;
506         char * reply;
507         unsigned int maxlen = 256;
508         int again = 1;
509
510         reply = MALLOC(maxlen);
511
512         while (again) {
513                 if (!reply) {
514                         if (tmp)
515                                 free(tmp);
516                         return 1;
517                 }
518                 c = tmp = reply;
519                 c += snprint_defaults(conf, c, reply + maxlen - c);
520                 again = ((c - reply) == maxlen);
521                 if (again) {
522                         reply = REALLOC(reply, maxlen *= 2);
523                         continue;
524                 }
525                 c += snprint_blacklist(conf, c, reply + maxlen - c);
526                 again = ((c - reply) == maxlen);
527                 if (again) {
528                         reply = REALLOC(reply, maxlen *= 2);
529                         continue;
530                 }
531                 c += snprint_blacklist_except(conf, c, reply + maxlen - c);
532                 again = ((c - reply) == maxlen);
533                 if (again) {
534                         reply = REALLOC(reply, maxlen *= 2);
535                         continue;
536                 }
537                 c += snprint_hwtable(conf, c, reply + maxlen - c, conf->hwtable);
538                 again = ((c - reply) == maxlen);
539                 if (again) {
540                         reply = REALLOC(reply, maxlen *= 2);
541                         continue;
542                 }
543                 c += snprint_overrides(conf, c, reply + maxlen - c,
544                                        conf->overrides);
545                 again = ((c - reply) == maxlen);
546                 if (again) {
547                         reply = REALLOC(reply, maxlen *= 2);
548                         continue;
549                 }
550                 if (VECTOR_SIZE(conf->mptable) > 0) {
551                         c += snprint_mptable(conf, c, reply + maxlen - c,
552                                              conf->mptable);
553                         again = ((c - reply) == maxlen);
554                         if (again)
555                                 reply = REALLOC(reply, maxlen *= 2);
556                 }
557         }
558
559         printf("%s", reply);
560         FREE(reply);
561         return 0;
562 }
563
564 static int
565 get_dev_type(char *dev) {
566         struct stat buf;
567         int i;
568
569         if (stat(dev, &buf) == 0 && S_ISBLK(buf.st_mode)) {
570                 if (dm_is_dm_major(major(buf.st_rdev)))
571                         return DEV_DEVMAP;
572                 return DEV_DEVNODE;
573         }
574         else if (sscanf(dev, "%d:%d", &i, &i) == 2)
575                 return DEV_DEVT;
576         else if (valid_alias(dev))
577                 return DEV_DEVMAP;
578         return DEV_NONE;
579 }
580
581 int
582 main (int argc, char *argv[])
583 {
584         int arg;
585         extern char *optarg;
586         extern int optind;
587         int r = 1;
588         enum mpath_cmds cmd = CMD_CREATE;
589         enum devtypes dev_type = DEV_NONE;
590         char *dev = NULL;
591         struct config *conf;
592         int retries = -1;
593
594         udev = udev_new();
595         logsink = 0;
596         conf = load_config(DEFAULT_CONFIGFILE);
597         if (!conf)
598                 exit(1);
599         multipath_conf = conf;
600         conf->retrigger_tries = 0;
601         while ((arg = getopt(argc, argv, ":adcChl::FfM:v:p:b:BrR:itquUwW")) != EOF ) {
602                 switch(arg) {
603                 case 1: printf("optarg : %s\n",optarg);
604                         break;
605                 case 'v':
606                         if (sizeof(optarg) > sizeof(char *) ||
607                             !isdigit(optarg[0])) {
608                                 usage (argv[0]);
609                                 exit(1);
610                         }
611
612                         conf->verbosity = atoi(optarg);
613                         break;
614                 case 'b':
615                         conf->bindings_file = strdup(optarg);
616                         break;
617                 case 'B':
618                         conf->bindings_read_only = 1;
619                         break;
620                 case 'q':
621                         conf->allow_queueing = 1;
622                         break;
623                 case 'c':
624                         cmd = CMD_VALID_PATH;
625                         break;
626                 case 'C':
627                         cmd = CMD_USABLE_PATHS;
628                         break;
629                 case 'd':
630                         if (cmd == CMD_CREATE)
631                                 cmd = CMD_DRY_RUN;
632                         break;
633                 case 'f':
634                         conf->remove = FLUSH_ONE;
635                         break;
636                 case 'F':
637                         conf->remove = FLUSH_ALL;
638                         break;
639                 case 'l':
640                         if (optarg && !strncmp(optarg, "l", 1))
641                                 cmd = CMD_LIST_LONG;
642                         else
643                                 cmd = CMD_LIST_SHORT;
644
645                         break;
646                 case 'M':
647 #if _DEBUG_
648                         debug = atoi(optarg);
649 #endif
650                         break;
651                 case 'p':
652                         conf->pgpolicy_flag = get_pgpolicy_id(optarg);
653                         if (conf->pgpolicy_flag == IOPOLICY_UNDEF) {
654                                 printf("'%s' is not a valid policy\n", optarg);
655                                 usage(argv[0]);
656                                 exit(1);
657                         }
658                         break;
659                 case 'r':
660                         conf->force_reload = FORCE_RELOAD_YES;
661                         break;
662                 case 'i':
663                         conf->ignore_wwids = 1;
664                         break;
665                 case 't':
666                         r = dump_config(conf);
667                         goto out_free_config;
668                 case 'h':
669                         usage(argv[0]);
670                         exit(0);
671                 case 'u':
672                         cmd = CMD_VALID_PATH;
673                         dev_type = DEV_UEVENT;
674                         break;
675                 case 'U':
676                         cmd = CMD_USABLE_PATHS;
677                         dev_type = DEV_UEVENT;
678                         break;
679                 case 'w':
680                         cmd = CMD_REMOVE_WWID;
681                         break;
682                 case 'W':
683                         cmd = CMD_RESET_WWIDS;
684                         break;
685                 case 'a':
686                         cmd = CMD_ADD_WWID;
687                         break;
688                 case 'R':
689                         retries = atoi(optarg);
690                         break;
691                 case ':':
692                         fprintf(stderr, "Missing option argument\n");
693                         usage(argv[0]);
694                         exit(1);
695                 case '?':
696                         fprintf(stderr, "Unknown switch: %s\n", optarg);
697                         usage(argv[0]);
698                         exit(1);
699                 default:
700                         usage(argv[0]);
701                         exit(1);
702                 }
703         }
704
705         /*
706          * FIXME: new device detection with find_multipaths currently
707          * doesn't work reliably.
708          */
709         if (cmd ==  CMD_VALID_PATH &&
710             conf->find_multipaths && conf->ignore_wwids) {
711                 condlog(2, "ignoring -i flag because find_multipath is set in multipath.conf");
712                 conf->ignore_wwids = 0;
713         }
714
715         if (getuid() != 0) {
716                 fprintf(stderr, "need to be root\n");
717                 exit(1);
718         }
719
720         if (optind < argc) {
721                 dev = MALLOC(FILE_NAME_SIZE);
722
723                 if (!dev)
724                         goto out;
725
726                 strncpy(dev, argv[optind], FILE_NAME_SIZE);
727                 if (dev_type != DEV_UEVENT)
728                         dev_type = get_dev_type(dev);
729                 if (dev_type == DEV_NONE) {
730                         condlog(0, "'%s' is not a valid argument\n", dev);
731                         goto out;
732                 }
733         }
734         if (dev_type == DEV_UEVENT) {
735                 openlog("multipath", 0, LOG_DAEMON);
736                 setlogmask(LOG_UPTO(conf->verbosity + 3));
737                 logsink = 1;
738         }
739
740         if (conf->max_fds) {
741                 struct rlimit fd_limit;
742
743                 fd_limit.rlim_cur = conf->max_fds;
744                 fd_limit.rlim_max = conf->max_fds;
745                 if (setrlimit(RLIMIT_NOFILE, &fd_limit) < 0)
746                         condlog(0, "can't set open fds limit to %d : %s",
747                                 conf->max_fds, strerror(errno));
748         }
749
750         libmp_udev_set_sync_support(1);
751
752         if (init_checkers(conf->multipath_dir)) {
753                 condlog(0, "failed to initialize checkers");
754                 goto out;
755         }
756         if (init_prio(conf->multipath_dir)) {
757                 condlog(0, "failed to initialize prioritizers");
758                 goto out;
759         }
760         if (cmd == CMD_USABLE_PATHS) {
761                 r = check_usable_paths(conf, dev, dev_type);
762                 goto out;
763         }
764         if (cmd == CMD_VALID_PATH &&
765             (!dev || dev_type == DEV_DEVMAP)) {
766                 condlog(0, "the -c option requires a path to check");
767                 goto out;
768         }
769         if (cmd == CMD_VALID_PATH &&
770             dev_type == DEV_UEVENT) {
771                 int fd;
772
773                 fd = mpath_connect();
774                 if (fd == -1) {
775                         condlog(3, "%s: daemon is not running", dev);
776                         if (!systemd_service_enabled(dev)) {
777                                 printf("%s is not a valid "
778                                        "multipath device path\n", dev);
779                                 goto out;
780                         }
781                 } else
782                         mpath_disconnect(fd);
783         }
784         if (cmd == CMD_REMOVE_WWID && !dev) {
785                 condlog(0, "the -w option requires a device");
786                 goto out;
787         }
788         if (cmd == CMD_RESET_WWIDS) {
789                 struct multipath * mpp;
790                 int i;
791                 vector curmp;
792
793                 curmp = vector_alloc();
794                 if (!curmp) {
795                         condlog(0, "can't allocate memory for mp list");
796                         goto out;
797                 }
798                 if (dm_get_maps(curmp) == 0)
799                         r = replace_wwids(curmp);
800                 if (r == 0)
801                         printf("successfully reset wwids\n");
802                 vector_foreach_slot_backwards(curmp, mpp, i) {
803                         vector_del_slot(curmp, i);
804                         free_multipath(mpp, KEEP_PATHS);
805                 }
806                 vector_free(curmp);
807                 goto out;
808         }
809         if (retries < 0)
810                 retries = conf->remove_retries;
811         if (conf->remove == FLUSH_ONE) {
812                 if (dev_type == DEV_DEVMAP) {
813                         r = dm_suspend_and_flush_map(dev, retries);
814                 } else
815                         condlog(0, "must provide a map name to remove");
816
817                 goto out;
818         }
819         else if (conf->remove == FLUSH_ALL) {
820                 r = dm_flush_maps(retries);
821                 goto out;
822         }
823         while ((r = configure(conf, cmd, dev_type, dev)) < 0)
824                 condlog(3, "restart multipath configuration process");
825
826 out:
827         dm_lib_release();
828         dm_lib_exit();
829
830         cleanup_prio();
831         cleanup_checkers();
832
833         if (dev_type == DEV_UEVENT)
834                 closelog();
835
836 out_free_config:
837         /*
838          * Freeing config must be done after dm_lib_exit(), because
839          * the logging function (dm_write_log()), which is called there,
840          * references the config.
841          */
842         free_config(conf);
843         conf = NULL;
844         udev_unref(udev);
845         if (dev)
846                 FREE(dev);
847 #ifdef _DEBUG_
848         dbg_free_final(NULL);
849 #endif
850         return r;
851 }