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