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