multipath: print sysfs state in fast list mode
[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, int quick)
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                                         pp->offline = 1;
175                                         continue;
176                                 }
177                                 pp->mpp = mpp;
178                                 if (quick)
179                                         continue;
180                                 conf = get_multipath_config();
181                                 if (pathinfo(pp, conf, DI_ALL))
182                                         pp->state = PATH_UNCHECKED;
183                                 put_multipath_config(conf);
184                                 continue;
185                         }
186                         pp->mpp = mpp;
187                         if (quick)
188                                 continue;
189                         if (pp->state == PATH_UNCHECKED ||
190                             pp->state == PATH_WILD) {
191                                 conf = get_multipath_config();
192                                 if (pathinfo(pp, conf, DI_CHECKER))
193                                         pp->state = PATH_UNCHECKED;
194                                 put_multipath_config(conf);
195                         }
196
197                         if (pp->priority == PRIO_UNDEF) {
198                                 conf = get_multipath_config();
199                                 if (pathinfo(pp, conf, DI_PRIO))
200                                         pp->priority = PRIO_UNDEF;
201                                 put_multipath_config(conf);
202                         }
203                 }
204         }
205         return 0;
206 }
207
208 static int
209 get_dm_mpvec (enum mpath_cmds cmd, vector curmp, vector pathvec, char * refwwid)
210 {
211         int i;
212         struct multipath * mpp;
213         char params[PARAMS_SIZE], status[PARAMS_SIZE];
214
215         if (dm_get_maps(curmp))
216                 return 1;
217
218         vector_foreach_slot (curmp, mpp, i) {
219                 /*
220                  * discard out of scope maps
221                  */
222                 if (refwwid && strlen(refwwid) &&
223                     strncmp(mpp->wwid, refwwid, WWID_SIZE)) {
224                         condlog(3, "skip map %s: out of scope", mpp->alias);
225                         free_multipath(mpp, KEEP_PATHS);
226                         vector_del_slot(curmp, i);
227                         i--;
228                         continue;
229                 }
230
231                 if (cmd == CMD_VALID_PATH)
232                         continue;
233
234                 dm_get_map(mpp->alias, &mpp->size, params);
235                 condlog(3, "params = %s", params);
236                 dm_get_status(mpp->alias, status);
237                 condlog(3, "status = %s", status);
238
239                 disassemble_map(pathvec, params, mpp, 0);
240
241                 /*
242                  * disassemble_map() can add new paths to pathvec.
243                  * If not in "fast list mode", we need to fetch information
244                  * about them
245                  */
246                 update_paths(mpp, (cmd == CMD_LIST_SHORT));
247
248                 if (cmd == CMD_LIST_LONG)
249                         mpp->bestpg = select_path_group(mpp);
250
251                 disassemble_status(status, mpp);
252
253                 if (cmd == CMD_LIST_SHORT ||
254                     cmd == CMD_LIST_LONG) {
255                         struct config *conf = get_multipath_config();
256                         print_multipath_topology(mpp, conf->verbosity);
257                         put_multipath_config(conf);
258                 }
259
260                 if (cmd == CMD_CREATE)
261                         reinstate_paths(mpp);
262         }
263         return 0;
264 }
265
266 static int check_usable_paths(struct config *conf,
267                               const char *devpath, enum devtypes dev_type)
268 {
269         struct udev_device *ud = NULL;
270         struct multipath *mpp = NULL;
271         struct pathgroup *pg;
272         struct path *pp;
273         char *mapname;
274         vector pathvec = NULL;
275         char params[PARAMS_SIZE], status[PARAMS_SIZE];
276         dev_t devt;
277         int r = 1, i, j;
278
279         ud = get_udev_device(devpath, dev_type);
280         if (ud == NULL)
281                 return r;
282
283         devt = udev_device_get_devnum(ud);
284         if (!dm_is_dm_major(major(devt))) {
285                 condlog(1, "%s is not a dm device", devpath);
286                 goto out;
287         }
288
289         mapname = dm_mapname(major(devt), minor(devt));
290         if (mapname == NULL) {
291                 condlog(1, "dm device not found: %s", devpath);
292                 goto out;
293         }
294
295         if (!dm_is_mpath(mapname)) {
296                 condlog(1, "%s is not a multipath map", devpath);
297                 goto free;
298         }
299
300         /* pathvec is needed for disassemble_map */
301         pathvec = vector_alloc();
302         if (pathvec == NULL)
303                 goto free;
304
305         mpp = dm_get_multipath(mapname);
306         if (mpp == NULL)
307                 goto free;
308
309         dm_get_map(mpp->alias, &mpp->size, params);
310         dm_get_status(mpp->alias, status);
311         disassemble_map(pathvec, params, mpp, 0);
312         disassemble_status(status, mpp);
313
314         vector_foreach_slot (mpp->pg, pg, i) {
315                 vector_foreach_slot (pg->paths, pp, j) {
316                         pp->udev = get_udev_device(pp->dev_t, DEV_DEVT);
317                         if (pp->udev == NULL)
318                                 continue;
319                         if (pathinfo(pp, conf, DI_SYSFS|DI_NOIO) != PATHINFO_OK)
320                                 continue;
321
322                         if (pp->state == PATH_UP &&
323                             pp->dmstate == PSTATE_ACTIVE) {
324                                 condlog(3, "%s: path %s is usable",
325                                         devpath, pp->dev);
326                                 r = 0;
327                                 goto found;
328                         }
329                 }
330         }
331 found:
332         condlog(r == 0 ? 3 : 2, "%s:%s usable paths found",
333                 devpath, r == 0 ? "" : " no");
334 free:
335         FREE(mapname);
336         free_multipath(mpp, FREE_PATHS);
337         vector_free(pathvec);
338 out:
339         udev_device_unref(ud);
340         return r;
341 }
342
343 /*
344  * Return value:
345  *  -1: Retry
346  *   0: Success
347  *   1: Failure
348  */
349 static int
350 configure (struct config *conf, enum mpath_cmds cmd,
351            enum devtypes dev_type, char *devpath)
352 {
353         vector curmp = NULL;
354         vector pathvec = NULL;
355         struct vectors vecs;
356         int r = 1;
357         int di_flag = 0;
358         char * refwwid = NULL;
359         char * dev = NULL;
360
361         /*
362          * allocate core vectors to store paths and multipaths
363          */
364         curmp = vector_alloc();
365         pathvec = vector_alloc();
366
367         if (!curmp || !pathvec) {
368                 condlog(0, "can not allocate memory");
369                 goto out;
370         }
371         vecs.pathvec = pathvec;
372         vecs.mpvec = curmp;
373
374         dev = convert_dev(devpath, (dev_type == DEV_DEVNODE));
375
376         /*
377          * if we have a blacklisted device parameter, exit early
378          */
379         if (dev && (dev_type == DEV_DEVNODE ||
380                     dev_type == DEV_UEVENT) &&
381             cmd != CMD_REMOVE_WWID &&
382             (filter_devnode(conf->blist_devnode,
383                             conf->elist_devnode, dev) > 0)) {
384                 if (cmd == CMD_VALID_PATH)
385                         printf("%s is not a valid multipath device path\n",
386                                devpath);
387                 goto out;
388         }
389
390         /*
391          * scope limiting must be translated into a wwid
392          * failing the translation is fatal (by policy)
393          */
394         if (devpath) {
395                 int failed = get_refwwid(cmd, devpath, dev_type,
396                                          pathvec, &refwwid);
397                 if (!refwwid) {
398                         condlog(4, "%s: failed to get wwid", devpath);
399                         if (failed == 2 && cmd == CMD_VALID_PATH)
400                                 printf("%s is not a valid multipath device path\n", devpath);
401                         else
402                                 condlog(3, "scope is null");
403                         goto out;
404                 }
405                 if (cmd == CMD_REMOVE_WWID) {
406                         r = remove_wwid(refwwid);
407                         if (r == 0)
408                                 printf("wwid '%s' removed\n", refwwid);
409                         else if (r == 1) {
410                                 printf("wwid '%s' not in wwids file\n",
411                                         refwwid);
412                                 r = 0;
413                         }
414                         goto out;
415                 }
416                 if (cmd == CMD_ADD_WWID) {
417                         r = remember_wwid(refwwid);
418                         if (r == 0)
419                                 printf("wwid '%s' added\n", refwwid);
420                         else
421                                 printf("failed adding '%s' to wwids file\n",
422                                        refwwid);
423                         goto out;
424                 }
425                 condlog(3, "scope limited to %s", refwwid);
426                 /* If you are ignoring the wwids file and find_multipaths is
427                  * set, you need to actually check if there are two available
428                  * paths to determine if this path should be multipathed. To
429                  * do this, we put off the check until after discovering all
430                  * the paths */
431                 if (cmd == CMD_VALID_PATH &&
432                     (!conf->find_multipaths || !conf->ignore_wwids)) {
433                         if (conf->ignore_wwids ||
434                             check_wwids_file(refwwid, 0) == 0)
435                                 r = 0;
436
437                         printf("%s %s a valid multipath device path\n",
438                                devpath, r == 0 ? "is" : "is not");
439                         goto out;
440                 }
441         }
442
443         /*
444          * get a path list
445          */
446         if (devpath)
447                 di_flag = DI_WWID;
448
449         if (cmd == CMD_LIST_LONG)
450                 /* extended path info '-ll' */
451                 di_flag |= DI_SYSFS | DI_CHECKER | DI_SERIAL;
452         else if (cmd == CMD_LIST_SHORT)
453                 /* minimum path info '-l' */
454                 di_flag |= DI_SYSFS;
455         else
456                 /* maximum info */
457                 di_flag = DI_ALL;
458
459         if (path_discovery(pathvec, di_flag) < 0)
460                 goto out;
461
462         if (conf->verbosity > 2)
463                 print_all_paths(pathvec, 1);
464
465         get_path_layout(pathvec, 0);
466
467         if (get_dm_mpvec(cmd, curmp, pathvec, refwwid))
468                 goto out;
469
470         filter_pathvec(pathvec, refwwid);
471
472
473         if (cmd == CMD_VALID_PATH) {
474                 /* This only happens if find_multipaths and
475                  * ignore_wwids is set.
476                  * If there is currently a multipath device matching
477                  * the refwwid, or there is more than one path matching
478                  * the refwwid, then the path is valid */
479                 if (VECTOR_SIZE(curmp) != 0 || VECTOR_SIZE(pathvec) > 1)
480                         r = 0;
481                 printf("%s %s a valid multipath device path\n",
482                        devpath, r == 0 ? "is" : "is not");
483                 goto out;
484         }
485
486         if (cmd != CMD_CREATE && cmd != CMD_DRY_RUN) {
487                 r = 0;
488                 goto out;
489         }
490
491         /*
492          * core logic entry point
493          */
494         r = coalesce_paths(&vecs, NULL, refwwid,
495                            conf->force_reload, cmd);
496
497 out:
498         if (refwwid)
499                 FREE(refwwid);
500
501         free_multipathvec(curmp, KEEP_PATHS);
502         free_pathvec(pathvec, FREE_PATHS);
503
504         return r;
505 }
506
507 static int
508 dump_config (struct config *conf)
509 {
510         char * c, * tmp = NULL;
511         char * reply;
512         unsigned int maxlen = 256;
513         int again = 1;
514
515         reply = MALLOC(maxlen);
516
517         while (again) {
518                 if (!reply) {
519                         if (tmp)
520                                 free(tmp);
521                         return 1;
522                 }
523                 c = tmp = reply;
524                 c += snprint_defaults(conf, c, reply + maxlen - c);
525                 again = ((c - reply) == maxlen);
526                 if (again) {
527                         reply = REALLOC(reply, maxlen *= 2);
528                         continue;
529                 }
530                 c += snprint_blacklist(conf, c, reply + maxlen - c);
531                 again = ((c - reply) == maxlen);
532                 if (again) {
533                         reply = REALLOC(reply, maxlen *= 2);
534                         continue;
535                 }
536                 c += snprint_blacklist_except(conf, c, reply + maxlen - c);
537                 again = ((c - reply) == maxlen);
538                 if (again) {
539                         reply = REALLOC(reply, maxlen *= 2);
540                         continue;
541                 }
542                 c += snprint_hwtable(conf, c, reply + maxlen - c, conf->hwtable);
543                 again = ((c - reply) == maxlen);
544                 if (again) {
545                         reply = REALLOC(reply, maxlen *= 2);
546                         continue;
547                 }
548                 c += snprint_overrides(conf, c, reply + maxlen - c,
549                                        conf->overrides);
550                 again = ((c - reply) == maxlen);
551                 if (again) {
552                         reply = REALLOC(reply, maxlen *= 2);
553                         continue;
554                 }
555                 if (VECTOR_SIZE(conf->mptable) > 0) {
556                         c += snprint_mptable(conf, c, reply + maxlen - c,
557                                              conf->mptable);
558                         again = ((c - reply) == maxlen);
559                         if (again)
560                                 reply = REALLOC(reply, maxlen *= 2);
561                 }
562         }
563
564         printf("%s", reply);
565         FREE(reply);
566         return 0;
567 }
568
569 static int
570 get_dev_type(char *dev) {
571         struct stat buf;
572         int i;
573
574         if (stat(dev, &buf) == 0 && S_ISBLK(buf.st_mode)) {
575                 if (dm_is_dm_major(major(buf.st_rdev)))
576                         return DEV_DEVMAP;
577                 return DEV_DEVNODE;
578         }
579         else if (sscanf(dev, "%d:%d", &i, &i) == 2)
580                 return DEV_DEVT;
581         else if (valid_alias(dev))
582                 return DEV_DEVMAP;
583         return DEV_NONE;
584 }
585
586 /*
587  * Some multipath commands are dangerous to run while multipathd is running.
588  * For example, "multipath -r" may apply a modified configuration to the kernel,
589  * while multipathd is still using the old configuration, leading to
590  * inconsistent state.
591  *
592  * It is safer to use equivalent multipathd client commands instead.
593  */
594 int delegate_to_multipathd(enum mpath_cmds cmd, const char *dev,
595                            enum devtypes dev_type, const struct config *conf)
596 {
597         int fd;
598         char command[1024], *p, *reply;
599         int n, r = 0;
600
601         fd = mpath_connect();
602         if (fd == -1)
603                 return 0;
604
605         p = command;
606         *p = '\0';
607         n = sizeof(command);
608
609         if (cmd == CMD_CREATE && conf->force_reload == FORCE_RELOAD_YES) {
610                 p += snprintf(p, n, "reconfigure");
611         }
612         /* Add other translations here */
613
614         if (strlen(command) == 0)
615                 /* No command found, no need to delegate */
616                 return 0;
617         else if (p >= command + sizeof(command)) {
618                 condlog(0, "internal error - command buffer overflow");
619                 r = -1;
620                 goto out;
621         }
622
623         condlog(3, "delegating command to multipathd");
624         r = mpath_process_cmd(fd, command, &reply, conf->uxsock_timeout);
625
626         if (r == -1) {
627                 condlog(1, "error in multipath command %s: %s",
628                         command, strerror(errno));
629                 goto out;
630         }
631
632         if (reply != NULL && *reply != '\0' && strcmp(reply, "ok\n"))
633                 printf("%s", reply);
634         r = 1;
635
636 out:
637         FREE(reply);
638         close(fd);
639         if (r < 0)
640                 exit(1);
641         return r;
642 }
643
644 int
645 main (int argc, char *argv[])
646 {
647         int arg;
648         extern char *optarg;
649         extern int optind;
650         int r = 1;
651         enum mpath_cmds cmd = CMD_CREATE;
652         enum devtypes dev_type = DEV_NONE;
653         char *dev = NULL;
654         struct config *conf;
655         int retries = -1;
656
657         udev = udev_new();
658         logsink = 0;
659         conf = load_config(DEFAULT_CONFIGFILE);
660         if (!conf)
661                 exit(1);
662         multipath_conf = conf;
663         conf->retrigger_tries = 0;
664         while ((arg = getopt(argc, argv, ":adcChl::FfM:v:p:b:BrR:itquUwW")) != EOF ) {
665                 switch(arg) {
666                 case 1: printf("optarg : %s\n",optarg);
667                         break;
668                 case 'v':
669                         if (sizeof(optarg) > sizeof(char *) ||
670                             !isdigit(optarg[0])) {
671                                 usage (argv[0]);
672                                 exit(1);
673                         }
674
675                         conf->verbosity = atoi(optarg);
676                         break;
677                 case 'b':
678                         conf->bindings_file = strdup(optarg);
679                         break;
680                 case 'B':
681                         conf->bindings_read_only = 1;
682                         break;
683                 case 'q':
684                         conf->allow_queueing = 1;
685                         break;
686                 case 'c':
687                         cmd = CMD_VALID_PATH;
688                         break;
689                 case 'C':
690                         cmd = CMD_USABLE_PATHS;
691                         break;
692                 case 'd':
693                         if (cmd == CMD_CREATE)
694                                 cmd = CMD_DRY_RUN;
695                         break;
696                 case 'f':
697                         conf->remove = FLUSH_ONE;
698                         break;
699                 case 'F':
700                         conf->remove = FLUSH_ALL;
701                         break;
702                 case 'l':
703                         if (optarg && !strncmp(optarg, "l", 1))
704                                 cmd = CMD_LIST_LONG;
705                         else
706                                 cmd = CMD_LIST_SHORT;
707
708                         break;
709                 case 'M':
710 #if _DEBUG_
711                         debug = atoi(optarg);
712 #endif
713                         break;
714                 case 'p':
715                         conf->pgpolicy_flag = get_pgpolicy_id(optarg);
716                         if (conf->pgpolicy_flag == IOPOLICY_UNDEF) {
717                                 printf("'%s' is not a valid policy\n", optarg);
718                                 usage(argv[0]);
719                                 exit(1);
720                         }
721                         break;
722                 case 'r':
723                         conf->force_reload = FORCE_RELOAD_YES;
724                         break;
725                 case 'i':
726                         conf->ignore_wwids = 1;
727                         break;
728                 case 't':
729                         r = dump_config(conf);
730                         goto out_free_config;
731                 case 'h':
732                         usage(argv[0]);
733                         exit(0);
734                 case 'u':
735                         cmd = CMD_VALID_PATH;
736                         dev_type = DEV_UEVENT;
737                         break;
738                 case 'U':
739                         cmd = CMD_USABLE_PATHS;
740                         dev_type = DEV_UEVENT;
741                         break;
742                 case 'w':
743                         cmd = CMD_REMOVE_WWID;
744                         break;
745                 case 'W':
746                         cmd = CMD_RESET_WWIDS;
747                         break;
748                 case 'a':
749                         cmd = CMD_ADD_WWID;
750                         break;
751                 case 'R':
752                         retries = atoi(optarg);
753                         break;
754                 case ':':
755                         fprintf(stderr, "Missing option argument\n");
756                         usage(argv[0]);
757                         exit(1);
758                 case '?':
759                         fprintf(stderr, "Unknown switch: %s\n", optarg);
760                         usage(argv[0]);
761                         exit(1);
762                 default:
763                         usage(argv[0]);
764                         exit(1);
765                 }
766         }
767
768         /*
769          * FIXME: new device detection with find_multipaths currently
770          * doesn't work reliably.
771          */
772         if (cmd ==  CMD_VALID_PATH &&
773             conf->find_multipaths && conf->ignore_wwids) {
774                 condlog(2, "ignoring -i flag because find_multipath is set in multipath.conf");
775                 conf->ignore_wwids = 0;
776         }
777
778         if (getuid() != 0) {
779                 fprintf(stderr, "need to be root\n");
780                 exit(1);
781         }
782
783         if (optind < argc) {
784                 dev = MALLOC(FILE_NAME_SIZE);
785
786                 if (!dev)
787                         goto out;
788
789                 strncpy(dev, argv[optind], FILE_NAME_SIZE);
790                 if (dev_type != DEV_UEVENT)
791                         dev_type = get_dev_type(dev);
792                 if (dev_type == DEV_NONE) {
793                         condlog(0, "'%s' is not a valid argument\n", dev);
794                         goto out;
795                 }
796         }
797         if (dev_type == DEV_UEVENT) {
798                 openlog("multipath", 0, LOG_DAEMON);
799                 setlogmask(LOG_UPTO(conf->verbosity + 3));
800                 logsink = 1;
801         }
802
803         if (conf->max_fds) {
804                 struct rlimit fd_limit;
805
806                 fd_limit.rlim_cur = conf->max_fds;
807                 fd_limit.rlim_max = conf->max_fds;
808                 if (setrlimit(RLIMIT_NOFILE, &fd_limit) < 0)
809                         condlog(0, "can't set open fds limit to %d : %s",
810                                 conf->max_fds, strerror(errno));
811         }
812
813         libmp_udev_set_sync_support(1);
814
815         if (init_checkers(conf->multipath_dir)) {
816                 condlog(0, "failed to initialize checkers");
817                 goto out;
818         }
819         if (init_prio(conf->multipath_dir)) {
820                 condlog(0, "failed to initialize prioritizers");
821                 goto out;
822         }
823         if (cmd == CMD_USABLE_PATHS) {
824                 r = check_usable_paths(conf, dev, dev_type);
825                 goto out;
826         }
827         if (cmd == CMD_VALID_PATH &&
828             (!dev || dev_type == DEV_DEVMAP)) {
829                 condlog(0, "the -c option requires a path to check");
830                 goto out;
831         }
832         if (cmd == CMD_VALID_PATH &&
833             dev_type == DEV_UEVENT) {
834                 int fd;
835
836                 fd = mpath_connect();
837                 if (fd == -1) {
838                         condlog(3, "%s: daemon is not running", dev);
839                         if (!systemd_service_enabled(dev)) {
840                                 printf("%s is not a valid "
841                                        "multipath device path\n", dev);
842                                 goto out;
843                         }
844                 } else
845                         mpath_disconnect(fd);
846         }
847
848         if (cmd == CMD_REMOVE_WWID && !dev) {
849                 condlog(0, "the -w option requires a device");
850                 goto out;
851         }
852
853         if (delegate_to_multipathd(cmd, dev, dev_type, conf))
854                 exit(0);
855
856         if (cmd == CMD_RESET_WWIDS) {
857                 struct multipath * mpp;
858                 int i;
859                 vector curmp;
860
861                 curmp = vector_alloc();
862                 if (!curmp) {
863                         condlog(0, "can't allocate memory for mp list");
864                         goto out;
865                 }
866                 if (dm_get_maps(curmp) == 0)
867                         r = replace_wwids(curmp);
868                 if (r == 0)
869                         printf("successfully reset wwids\n");
870                 vector_foreach_slot_backwards(curmp, mpp, i) {
871                         vector_del_slot(curmp, i);
872                         free_multipath(mpp, KEEP_PATHS);
873                 }
874                 vector_free(curmp);
875                 goto out;
876         }
877         if (retries < 0)
878                 retries = conf->remove_retries;
879         if (conf->remove == FLUSH_ONE) {
880                 if (dev_type == DEV_DEVMAP) {
881                         r = dm_suspend_and_flush_map(dev, retries);
882                 } else
883                         condlog(0, "must provide a map name to remove");
884
885                 goto out;
886         }
887         else if (conf->remove == FLUSH_ALL) {
888                 r = dm_flush_maps(retries);
889                 goto out;
890         }
891         while ((r = configure(conf, cmd, dev_type, dev)) < 0)
892                 condlog(3, "restart multipath configuration process");
893
894 out:
895         dm_lib_release();
896         dm_lib_exit();
897
898         cleanup_prio();
899         cleanup_checkers();
900
901         if (dev_type == DEV_UEVENT)
902                 closelog();
903
904 out_free_config:
905         /*
906          * Freeing config must be done after dm_lib_exit(), because
907          * the logging function (dm_write_log()), which is called there,
908          * references the config.
909          */
910         free_config(conf);
911         conf = NULL;
912         udev_unref(udev);
913         if (dev)
914                 FREE(dev);
915 #ifdef _DEBUG_
916         dbg_free_final(NULL);
917 #endif
918         return r;
919 }