2 * Soft: multipath device mapper target autoconfig
4 * Version: $Id: main.h,v 0.0.1 2003/09/18 15:13:38 cvaroqui Exp $
6 * Author: Christophe Varoqui
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.
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.
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
25 #include <sys/types.h>
38 #include <libdevmapper.h>
39 #include "devmapper.h"
44 #include "structs_vec.h"
47 #include "blacklist.h"
48 #include "discovery.h"
50 #include "switchgroup.h"
51 #include "dm-generic.h"
54 #include "configure.h"
55 #include "pgpolicies.h"
60 #include "mpath_cmd.h"
63 #include "time-util.h"
69 * Return values of configure(), check_path_valid(), and main().
74 RTVL_RETRY, /* returned by configure(), not by main() */
78 dump_config (struct config *conf, vector hwes, vector mpvec)
80 char * reply = snprint_config(conf, NULL, hwes, mpvec);
90 void rcu_register_thread_memb(void) {}
92 void rcu_unregister_thread_memb(void) {}
95 filter_pathvec (vector pathvec, const char *refwwid)
100 if (!refwwid || !strlen(refwwid))
103 vector_foreach_slot (pathvec, pp, i) {
104 if (strncmp(pp->wwid, refwwid, WWID_SIZE) != 0) {
105 condlog(3, "skip path %s : out of scope", pp->dev);
107 vector_del_slot(pathvec, i);
115 usage (char * progname)
117 fprintf (stderr, VERSION_STRING);
118 fprintf (stderr, "Usage:\n");
119 fprintf (stderr, " %s [-v level] [-B|-d|-i|-q|-r] [-b file] [-p policy] [device]\n", progname);
120 fprintf (stderr, " %s [-v level] [-R retries] -f device\n", progname);
121 fprintf (stderr, " %s [-v level] [-R retries] -F\n", progname);
122 fprintf (stderr, " %s [-v level] [-l|-ll] [device]\n", progname);
123 fprintf (stderr, " %s [-v level] [-a|-w] device\n", progname);
124 fprintf (stderr, " %s [-v level] -W\n", progname);
125 fprintf (stderr, " %s [-v level] [-i] [-c|-C] device\n", progname);
126 fprintf (stderr, " %s [-v level] [-i] [-u|-U]\n", progname);
127 fprintf (stderr, " %s [-h|-t|-T]\n", progname);
131 " -h print this usage text\n"
132 " -l show multipath topology (sysfs and DM info)\n"
133 " -ll show multipath topology (maximum info)\n"
134 " -e enable foreign libraries with -l/-ll\n"
135 " -f flush a multipath device map\n"
136 " -F flush all multipath device maps\n"
137 " -a add a device wwid to the wwids file\n"
138 " -c check if a device should be a path in a multipath device\n"
139 " -C check if a multipath device has usable paths\n"
140 " -q allow queue_if_no_path when multipathd is not running\n"
141 " -d dry run, do not create or update devmaps\n"
142 " -t display the currently used multipathd configuration\n"
143 " -T display the multipathd configuration without builtin defaults\n"
144 " -r force devmap reload\n"
145 " -i ignore wwids file\n"
146 " -B treat the bindings file as read only\n"
147 " -b fil bindings file location\n"
148 " -w remove a device from the wwids file\n"
149 " -W reset the wwids file include only the current devices\n"
150 " -R num number of times to retry removes of in-use devices\n"
151 " -u check if the device specified in the program environment should be a\n"
152 " path in a multipath device\n"
153 " -U check if the device specified in the program environment is a\n"
154 " multipath device with usable paths, see -C flag\n"
155 " -p pol force all maps to specified path grouping policy:\n"
156 " . failover one path per priority group\n"
157 " . multibus all paths in one priority group\n"
158 " . group_by_serial one priority group per serial\n"
159 " . group_by_prio one priority group per priority lvl\n"
160 " . group_by_node_name one priority group per target node\n"
161 " -v lvl verbosity level:\n"
163 " . 1 print created devmap names only\n"
164 " . 2 default verbosity\n"
165 " . 3 print debug information\n"
166 " device action limited to:\n"
167 " . multipath named 'device' (ex: mpath0)\n"
168 " . multipath whose wwid is 'device' (ex: 60051...)\n"
169 " . multipath including the path named 'device' (ex: /dev/sda or\n"
171 " . multipath including the path with maj:min 'device' (ex: 8:0)\n"
177 get_dm_mpvec (enum mpath_cmds cmd, vector curmp, vector pathvec, char * refwwid)
180 struct multipath * mpp;
181 int flags = (cmd == CMD_LIST_SHORT ? DI_NOIO : DI_ALL);
183 if (dm_get_maps(curmp))
186 vector_foreach_slot (curmp, mpp, i) {
188 * discard out of scope maps
190 if (refwwid && strlen(refwwid) &&
191 strncmp(mpp->wwid, refwwid, WWID_SIZE)) {
192 condlog(3, "skip map %s: out of scope", mpp->alias);
193 remove_map(mpp, pathvec, curmp);
198 if (update_multipath_table(mpp, pathvec, flags) != DMP_OK) {
199 condlog(1, "error parsing map %s", mpp->wwid);
200 remove_map(mpp, pathvec, curmp);
205 if (cmd == CMD_LIST_LONG)
206 mpp->bestpg = select_path_group(mpp);
208 if (cmd == CMD_LIST_SHORT ||
209 cmd == CMD_LIST_LONG)
210 print_multipath_topology(mpp, libmp_verbosity);
212 if (cmd == CMD_CREATE)
213 reinstate_paths(mpp);
216 if (cmd == CMD_LIST_SHORT || cmd == CMD_LIST_LONG)
217 print_foreign_topology(libmp_verbosity);
222 static int check_usable_paths(struct config *conf,
223 const char *devpath, enum devtypes dev_type)
225 struct udev_device *ud = NULL;
226 struct multipath *mpp = NULL;
227 struct pathgroup *pg;
230 vector pathvec = NULL;
234 ud = get_udev_device(devpath, dev_type);
238 devt = udev_device_get_devnum(ud);
239 if (!dm_is_dm_major(major(devt))) {
240 condlog(1, "%s is not a dm device", devpath);
244 mapname = dm_mapname(major(devt), minor(devt));
245 if (mapname == NULL) {
246 condlog(1, "dm device not found: %s", devpath);
250 if (dm_is_mpath(mapname) != 1) {
251 condlog(1, "%s is not a multipath map", devpath);
255 /* pathvec is needed for disassemble_map */
256 pathvec = vector_alloc();
260 mpp = dm_get_multipath(mapname);
264 if (update_multipath_table(mpp, pathvec, 0) != DMP_OK)
267 vector_foreach_slot (mpp->pg, pg, i) {
268 vector_foreach_slot (pg->paths, pp, j) {
269 pp->udev = get_udev_device(pp->dev_t, DEV_DEVT);
270 if (pp->udev == NULL)
272 if (pathinfo(pp, conf, DI_SYSFS|DI_NOIO|DI_CHECKER) != PATHINFO_OK)
275 if (pp->state == PATH_UP &&
276 pp->dmstate == PSTATE_ACTIVE) {
277 condlog(3, "%s: path %s is usable",
285 condlog(r == 0 ? 3 : 2, "%s:%s usable paths found",
286 devpath, r == 0 ? "" : " no");
289 free_multipath(mpp, FREE_PATHS);
290 vector_free(pathvec);
292 udev_device_unref(ud);
297 FIND_MULTIPATHS_WAIT_DONE = 0,
298 FIND_MULTIPATHS_WAITING = 1,
299 FIND_MULTIPATHS_ERROR = -1,
300 FIND_MULTIPATHS_NEVER = -2,
303 static const char shm_find_mp_dir[] = MULTIPATH_SHM_BASE "find_multipaths";
306 * find_multipaths_check_timeout(wwid, tmo)
307 * Helper for "find_multipaths smart"
309 * @param[in] pp: path to check / record
310 * @param[in] tmo: configured timeout for this WWID, or value <= 0 for checking
311 * @param[out] until: timestamp until we must wait, CLOCK_REALTIME, if return
312 * value is FIND_MULTIPATHS_WAITING
313 * @returns: FIND_MULTIPATHS_WAIT_DONE, if waiting has finished
314 * @returns: FIND_MULTIPATHS_ERROR, if internal error occurred
315 * @returns: FIND_MULTIPATHS_NEVER, if tmo is 0 and we didn't wait for this
317 * @returns: FIND_MULTIPATHS_WAITING, if timeout hasn't expired
319 static int find_multipaths_check_timeout(const struct path *pp, long tmo,
320 struct timespec *until)
323 struct timespec now, ftimes[2], tdiff;
328 clock_gettime(CLOCK_REALTIME, &now);
330 if (safe_sprintf(path, "%s/%s", shm_find_mp_dir, pp->dev_t)) {
331 condlog(1, "%s: path name overflow", __func__);
332 return FIND_MULTIPATHS_ERROR;
335 if (ensure_directories_exist(path, 0700)) {
336 condlog(1, "%s: error creating directories", __func__);
337 return FIND_MULTIPATHS_ERROR;
341 fd = open(path, O_RDONLY);
343 pthread_cleanup_push(close_fd, (void *)fd);
345 pthread_cleanup_pop(1);
347 } else if (tmo > 0) {
349 fd = open(path, O_RDWR|O_EXCL|O_CREAT, 0644);
351 if (errno == EEXIST && !retries++)
352 /* We could have raced with another process */
354 condlog(1, "%s: error opening %s: %s",
355 __func__, path, strerror(errno));
356 return FIND_MULTIPATHS_ERROR;
359 pthread_cleanup_push(close_fd, (void *)fd);
361 * We just created the file. Set st_mtim to our desired
364 ftimes[0].tv_sec = 0;
365 ftimes[0].tv_nsec = UTIME_OMIT;
366 ftimes[1].tv_sec = now.tv_sec + tmo;
367 ftimes[1].tv_nsec = now.tv_nsec;
368 if (futimens(fd, ftimes) != 0) {
369 condlog(1, "%s: error in futimens(%s): %s", __func__,
370 path, strerror(errno));
373 pthread_cleanup_pop(1);
375 return FIND_MULTIPATHS_NEVER;
378 condlog(1, "%s: error in fstat for %s: %m", __func__, path);
379 return FIND_MULTIPATHS_ERROR;
382 timespecsub(&st.st_mtim, &now, &tdiff);
384 if (tdiff.tv_sec <= 0)
385 return FIND_MULTIPATHS_WAIT_DONE;
388 return FIND_MULTIPATHS_WAITING;
391 static int print_cmd_valid(int k, const vector pathvec,
394 int wait = FIND_MULTIPATHS_NEVER;
395 struct timespec until;
398 if (k != PATH_IS_VALID && k != PATH_IS_NOT_VALID &&
399 k != PATH_IS_MAYBE_VALID)
400 return PATH_IS_NOT_VALID;
402 if (k == PATH_IS_MAYBE_VALID) {
404 * Caller ensures that pathvec[0] is the path to
407 pp = VECTOR_SLOT(pathvec, 0);
408 select_find_multipaths_timeout(conf, pp);
409 wait = find_multipaths_check_timeout(
410 pp, pp->find_multipaths_timeout, &until);
411 if (wait != FIND_MULTIPATHS_WAITING)
412 k = PATH_IS_NOT_VALID;
413 } else if (pathvec != NULL && (pp = VECTOR_SLOT(pathvec, 0)))
414 wait = find_multipaths_check_timeout(pp, 0, &until);
415 if (wait == FIND_MULTIPATHS_WAITING)
416 printf("FIND_MULTIPATHS_WAIT_UNTIL=\"%ld.%06ld\"\n",
417 (long)until.tv_sec, until.tv_nsec/1000);
418 else if (wait == FIND_MULTIPATHS_WAIT_DONE)
419 printf("FIND_MULTIPATHS_WAIT_UNTIL=\"0\"\n");
420 printf("DM_MULTIPATH_DEVICE_PATH=\"%d\"\n",
421 k == PATH_IS_MAYBE_VALID ? 2 : k == PATH_IS_VALID ? 1 : 0);
422 /* Never return RTVL_MAYBE */
423 return k == PATH_IS_NOT_VALID ? PATH_IS_NOT_VALID : PATH_IS_VALID;
427 * Returns true if this device has been handled before,
428 * and released to systemd.
430 * This must be called before get_refwwid(),
431 * otherwise udev_device_new_from_environment() will have
432 * destroyed environ(7).
434 static bool released_to_systemd(void)
436 static const char dmdp[] = "DM_MULTIPATH_DEVICE_PATH";
437 const char *dm_mp_dev_path = getenv(dmdp);
440 ret = dm_mp_dev_path != NULL && !strcmp(dm_mp_dev_path, "0");
441 condlog(4, "%s: %s=%s -> %d", __func__, dmdp, dm_mp_dev_path, ret);
445 static struct vectors vecs;
446 static void cleanup_vecs(void)
448 free_multipathvec(vecs.mpvec, KEEP_PATHS);
449 free_pathvec(vecs.pathvec, FREE_PATHS);
453 configure (struct config *conf, enum mpath_cmds cmd,
454 enum devtypes dev_type, char *devpath)
457 vector pathvec = NULL;
459 int r = RTVL_FAIL, rc;
461 char * refwwid = NULL;
463 fieldwidth_t *width __attribute__((cleanup(cleanup_ucharp))) = NULL;
466 * allocate core vectors to store paths and multipaths
468 curmp = vector_alloc();
469 pathvec = vector_alloc();
470 newmp = vector_alloc();
472 if (!curmp || !pathvec || !newmp) {
473 condlog(0, "can not allocate memory");
476 vecs.pathvec = pathvec;
479 dev = convert_dev(devpath, (dev_type == DEV_DEVNODE));
482 * if we have a blacklisted device parameter, exit early
484 if (dev && (dev_type == DEV_DEVNODE ||
485 dev_type == DEV_UEVENT) &&
486 cmd != CMD_REMOVE_WWID &&
487 (filter_devnode(conf->blist_devnode,
488 conf->elist_devnode, dev) > 0)) {
493 * scope limiting must be translated into a wwid
494 * failing the translation is fatal (by policy)
497 get_refwwid(cmd, devpath, dev_type, pathvec, &refwwid);
499 condlog(4, "%s: failed to get wwid", devpath);
500 condlog(3, "scope is null");
503 if (cmd == CMD_REMOVE_WWID) {
504 rc = remove_wwid(refwwid);
506 printf("wwid '%s' removed\n", refwwid);
508 } else if (rc == 1) {
509 printf("wwid '%s' not in wwids file\n",
515 if (cmd == CMD_ADD_WWID) {
516 rc = remember_wwid(refwwid);
518 printf("wwid '%s' added\n", refwwid);
521 printf("failed adding '%s' to wwids file\n",
525 condlog(3, "scope limited to %s", refwwid);
534 if (cmd == CMD_LIST_LONG)
535 /* extended path info '-ll' */
536 di_flag |= DI_SYSFS | DI_CHECKER | DI_SERIAL;
537 else if (cmd == CMD_LIST_SHORT)
538 /* minimum path info '-l' */
544 if (path_discovery(pathvec, di_flag) < 0)
547 if (libmp_verbosity > 2)
548 print_all_paths(pathvec, 1);
550 if ((width = alloc_path_layout()) == NULL)
552 get_path_layout(pathvec, 0, width);
553 foreign_path_layout(width);
555 if (get_dm_mpvec(cmd, curmp, pathvec, refwwid))
558 filter_pathvec(pathvec, refwwid);
560 if (cmd == CMD_DUMP_CONFIG) {
561 vector hwes = get_used_hwes(pathvec);
563 dump_config(conf, hwes, curmp);
569 if (cmd != CMD_CREATE && cmd != CMD_DRY_RUN) {
575 * core logic entry point
577 rc = coalesce_paths(&vecs, newmp, refwwid,
578 conf->force_reload, cmd);
579 r = rc == CP_RETRY ? RTVL_RETRY : rc == CP_OK ? RTVL_OK : RTVL_FAIL;
583 (cmd == CMD_LIST_SHORT || cmd == CMD_LIST_LONG ||
584 cmd == CMD_CREATE) &&
585 (VECTOR_SIZE(curmp) > 0 || VECTOR_SIZE(newmp) > 0) &&
587 condlog(2, "Warning: multipath devices exist, but multipathd service is not running");
592 free_multipathvec(curmp, KEEP_PATHS);
594 free_multipathvec(newmp, KEEP_PATHS);
595 free_pathvec(pathvec, FREE_PATHS);
602 check_path_valid(const char *name, struct config *conf, bool is_uevent)
604 int fd, r = PATH_IS_ERROR;
606 vector pathvec = NULL;
613 r = is_path_valid(name, conf, pp, is_uevent);
614 if (r <= PATH_IS_ERROR || r >= PATH_MAX_VALID_RESULT)
617 /* set path values if is_path_valid() didn't */
619 pp->udev = udev_device_new_from_subsystem_sysname(udev, "block",
624 if (!strlen(pp->dev_t)) {
625 dev_t devt = udev_device_get_devnum(pp->udev);
626 if (major(devt) == 0 && minor(devt) == 0)
628 snprintf(pp->dev_t, BLK_DEV_SIZE, "%d:%d", major(devt),
632 if ((r == PATH_IS_VALID || r == PATH_IS_MAYBE_VALID) &&
633 released_to_systemd())
634 r = PATH_IS_NOT_VALID;
636 /* This state is only used to skip the released_to_systemd() check */
637 if (r == PATH_IS_VALID_NO_CHECK)
640 if (r != PATH_IS_MAYBE_VALID)
644 * If opening the path with O_EXCL fails, the path
645 * is in use (e.g. mounted during initramfs processing).
646 * We know that it's not used by dm-multipath.
647 * We may not set SYSTEMD_READY=0 on such devices, it
648 * might cause systemd to umount the device.
649 * Use O_RDONLY, because udevd would trigger another
650 * uevent for close-after-write.
652 * The O_EXCL check is potentially dangerous, because it may
653 * race with other tasks trying to access the device. Therefore
654 * this code is only executed if the path hasn't been released
655 * to systemd earlier (see above).
657 fd = open(udev_device_get_devnode(pp->udev), O_RDONLY|O_EXCL);
661 condlog(3, "%s: path %s is in use: %m", __func__, pp->dev);
662 /* Check if we raced with multipathd */
663 if (sysfs_is_multipathed(pp, false))
666 r = PATH_IS_NOT_VALID;
670 pathvec = vector_alloc();
674 if (store_path(pathvec, pp) != 0) {
679 /* make sure path isn't freed twice */
684 /* For find_multipaths = SMART, if there is more than one path
685 * matching the refwwid, then the path is valid */
686 if (path_discovery(pathvec, DI_SYSFS | DI_WWID) < 0)
688 filter_pathvec(pathvec, wwid);
689 if (VECTOR_SIZE(pathvec) > 1)
692 r = PATH_IS_MAYBE_VALID;
695 r = print_cmd_valid(r, pathvec, conf);
697 * multipath -u must exit with status 0, otherwise udev won't
700 if (!is_uevent && r == PATH_IS_NOT_VALID)
713 free_pathvec(pathvec, FREE_PATHS);
718 get_dev_type(char *dev) {
722 if (stat(dev, &buf) == 0 && S_ISBLK(buf.st_mode)) {
723 if (dm_is_dm_major(major(buf.st_rdev)))
727 else if (sscanf(dev, "%d:%d", &i, &i) == 2)
729 else if (valid_alias(dev))
735 * Some multipath commands are dangerous to run while multipathd is running.
736 * For example, "multipath -r" may apply a modified configuration to the kernel,
737 * while multipathd is still using the old configuration, leading to
738 * inconsistent state.
740 * It is safer to use equivalent multipathd client commands instead.
748 int delegate_to_multipathd(enum mpath_cmds cmd,
749 __attribute__((unused)) const char *dev,
750 __attribute__((unused)) enum devtypes dev_type,
751 const struct config *conf)
754 char command[1024], *p, *reply = NULL;
755 int n, r = DELEGATE_ERROR;
761 if (conf->skip_delegate)
762 return NOT_DELEGATED;
764 if (cmd == CMD_CREATE && conf->force_reload == FORCE_RELOAD_YES) {
765 p += snprintf(p, n, "reconfigure all");
767 else if (cmd == CMD_FLUSH_ONE && dev && dev_type == DEV_DEVMAP) {
768 p += snprintf(p, n, "del map %s", dev);
769 /* multipathd doesn't try as hard, to avoid potentially
770 * hanging. If it fails, retry with the regular multipath
774 else if (cmd == CMD_FLUSH_ALL) {
775 p += snprintf(p, n, "del maps");
776 /* multipathd doesn't try as hard, to avoid potentially
777 * hanging. If it fails, retry with the regular multipath
781 /* Add other translations here */
783 if (strlen(command) == 0)
784 /* No command found, no need to delegate */
785 return NOT_DELEGATED;
787 fd = mpath_connect();
789 return NOT_DELEGATED;
791 if (p >= command + sizeof(command)) {
792 condlog(0, "internal error - command buffer overflow");
796 condlog(3, "delegating command to multipathd");
798 if (mpath_process_cmd(fd, command, &reply, conf->uxsock_timeout)
800 condlog(1, "error in multipath command %s: %s",
801 command, strerror(errno));
805 if (reply != NULL && *reply != '\0') {
806 if (strcmp(reply, "fail\n"))
808 if (r != NOT_DELEGATED && strcmp(reply, "ok\n"))
819 main (int argc, char *argv[])
825 enum mpath_cmds cmd = CMD_CREATE;
826 enum devtypes dev_type = DEV_NONE;
830 bool enable_foreign = false;
833 if (atexit(dm_lib_exit) || atexit(libmultipath_exit))
834 condlog(1, "failed to register cleanup handler for libmultipath: %m");
835 logsink = LOGSINK_STDERR_WITH_TIME;
836 if (init_config(DEFAULT_CONFIGFILE))
838 if (atexit(uninit_config))
839 condlog(1, "failed to register cleanup handler for config: %m");
840 conf = get_multipath_config();
841 conf->retrigger_tries = 0;
842 conf->force_sync = 1;
843 if (atexit(cleanup_vecs))
844 condlog(1, "failed to register cleanup handler for vecs: %m");
845 while ((arg = getopt(argc, argv, ":adDcChl::eFfM:v:p:b:BrR:itTquUwW")) != EOF ) {
848 if (!isdigit(optarg[0])) {
853 libmp_verbosity = atoi(optarg);
856 conf->bindings_file = strdup(optarg);
859 conf->bindings_read_only = 1;
862 conf->allow_queueing = 1;
865 cmd = CMD_VALID_PATH;
868 cmd = CMD_USABLE_PATHS;
871 if (cmd == CMD_CREATE)
875 conf->skip_delegate = 1;
884 if (optarg && !strncmp(optarg, "l", 1))
887 cmd = CMD_LIST_SHORT;
893 conf->pgpolicy_flag = get_pgpolicy_id(optarg);
894 if (conf->pgpolicy_flag == IOPOLICY_UNDEF) {
895 printf("'%s' is not a valid policy\n", optarg);
901 conf->force_reload = FORCE_RELOAD_YES;
904 if (conf->find_multipaths == FIND_MULTIPATHS_ON ||
905 conf->find_multipaths == FIND_MULTIPATHS_STRICT)
906 conf->find_multipaths = FIND_MULTIPATHS_SMART;
907 else if (conf->find_multipaths == FIND_MULTIPATHS_OFF)
908 conf->find_multipaths = FIND_MULTIPATHS_GREEDY;
911 r = dump_config(conf, NULL, NULL) ? RTVL_FAIL : RTVL_OK;
914 cmd = CMD_DUMP_CONFIG;
920 cmd = CMD_VALID_PATH;
921 dev_type = DEV_UEVENT;
924 cmd = CMD_USABLE_PATHS;
925 dev_type = DEV_UEVENT;
928 cmd = CMD_REMOVE_WWID;
931 cmd = CMD_RESET_WWIDS;
937 retries = atoi(optarg);
940 enable_foreign = true;
943 fprintf(stderr, "Missing option argument\n");
947 fprintf(stderr, "Unknown switch: %s\n", optarg);
957 fprintf(stderr, "need to be root\n");
961 if (check_alias_settings(conf)) {
962 fprintf(stderr, "fatal configuration error, aborting");
967 dev = calloc(1, FILE_NAME_SIZE);
972 strlcpy(dev, argv[optind], FILE_NAME_SIZE);
973 if (dev_type != DEV_UEVENT)
974 dev_type = get_dev_type(dev);
975 if (dev_type == DEV_NONE) {
976 condlog(0, "'%s' is not a valid argument\n", dev);
979 if (dev_type == DEV_DEVNODE || dev_type == DEV_DEVT)
982 if (dev_type == DEV_UEVENT) {
983 openlog("multipath", 0, LOG_DAEMON);
984 setlogmask(LOG_UPTO(libmp_verbosity + 3));
985 logsink = LOGSINK_SYSLOG;
988 set_max_fds(conf->max_fds);
990 libmp_udev_set_sync_support(1);
992 if (init_checkers(conf->multipath_dir)) {
993 condlog(0, "failed to initialize checkers");
996 if (init_prio(conf->multipath_dir)) {
997 condlog(0, "failed to initialize prioritizers");
1001 if ((cmd == CMD_LIST_SHORT || cmd == CMD_LIST_LONG) && enable_foreign)
1002 conf->enable_foreign = strdup("");
1004 /* Failing here is non-fatal */
1005 init_foreign(conf->multipath_dir, conf->enable_foreign);
1006 if (cmd == CMD_USABLE_PATHS) {
1007 r = check_usable_paths(conf, dev, dev_type) ?
1008 RTVL_FAIL : RTVL_OK;
1011 if (cmd == CMD_VALID_PATH &&
1012 (!dev || dev_type == DEV_DEVMAP)) {
1013 condlog(0, "the -c option requires a path to check");
1016 if (cmd == CMD_VALID_PATH) {
1017 char * name = convert_dev(dev, (dev_type == DEV_DEVNODE));
1018 r = check_path_valid(name, conf, dev_type == DEV_UEVENT);
1022 if (cmd == CMD_REMOVE_WWID && !dev) {
1023 condlog(0, "the -w option requires a device");
1026 if (cmd == CMD_FLUSH_ONE && dev_type != DEV_DEVMAP) {
1027 condlog(0, "the -f option requires a map name to remove");
1031 switch(delegate_to_multipathd(cmd, dev, dev_type, conf)) {
1034 case DELEGATE_ERROR:
1040 if (cmd == CMD_RESET_WWIDS) {
1041 struct multipath * mpp;
1045 curmp = vector_alloc();
1047 condlog(0, "can't allocate memory for mp list");
1050 if (dm_get_maps(curmp) == 0)
1051 r = replace_wwids(curmp) ? RTVL_FAIL : RTVL_OK;
1053 printf("successfully reset wwids\n");
1054 vector_foreach_slot_backwards(curmp, mpp, i) {
1055 vector_del_slot(curmp, i);
1056 free_multipath(mpp, KEEP_PATHS);
1062 retries = conf->remove_retries;
1063 if (cmd == CMD_FLUSH_ONE) {
1064 r = dm_suspend_and_flush_map(dev, retries) ?
1065 RTVL_FAIL : RTVL_OK;
1068 else if (cmd == CMD_FLUSH_ALL) {
1069 r = dm_flush_maps(1, retries) ? RTVL_FAIL : RTVL_OK;
1072 while ((r = configure(conf, cmd, dev_type, dev)) == RTVL_RETRY)
1073 condlog(3, "restart multipath configuration process");
1076 put_multipath_config(conf);
1080 if (dev_type == DEV_UEVENT)