r291 - in multipath-tools/trunk: . devmap_name kpartx libcheckers libmultipath multipath multipathd path_priority/pp_alua path_priority/pp_balance_units path_priority/pp_emc path_priority/pp_netapp path_priority/pp_random path_priority/pp_tpc

Bastian Blank waldi at costa.debian.org
Mon Mar 13 15:16:47 UTC 2006


Author: waldi
Date: Mon Mar 13 15:16:41 2006
New Revision: 291

Added:
   multipath-tools/trunk/kpartx/dasd.c
   multipath-tools/trunk/kpartx/dasd.h
   multipath-tools/trunk/kpartx/mac.c
   multipath-tools/trunk/kpartx/mac.h
   multipath-tools/trunk/libcheckers/checkers.c
   multipath-tools/trunk/libcheckers/directio.h
   multipath-tools/trunk/libcheckers/emc_clariion.h
   multipath-tools/trunk/libcheckers/hp_sw.h
   multipath-tools/trunk/libcheckers/readsector0.h
   multipath-tools/trunk/libcheckers/tur.h
   multipath-tools/trunk/libmultipath/configure.c
   multipath-tools/trunk/libmultipath/configure.h
   multipath-tools/trunk/libmultipath/structs_vec.c
   multipath-tools/trunk/libmultipath/structs_vec.h
   multipath-tools/trunk/path_priority/pp_netapp/
   multipath-tools/trunk/path_priority/pp_netapp/Makefile
   multipath-tools/trunk/path_priority/pp_netapp/pp_netapp.c
   multipath-tools/trunk/path_priority/pp_tpc/
   multipath-tools/trunk/path_priority/pp_tpc/Makefile
   multipath-tools/trunk/path_priority/pp_tpc/pp_tpc.c
Removed:
   multipath-tools/trunk/libcheckers/path_state.h
   multipath-tools/trunk/libcheckers/selector.c
   multipath-tools/trunk/libmultipath/cache.c
   multipath-tools/trunk/libmultipath/cache.h
Modified:
   multipath-tools/trunk/   (props changed)
   multipath-tools/trunk/ChangeLog
   multipath-tools/trunk/FAQ
   multipath-tools/trunk/Makefile.inc
   multipath-tools/trunk/README
   multipath-tools/trunk/TODO
   multipath-tools/trunk/devmap_name/Makefile
   multipath-tools/trunk/devmap_name/devmap_name.c
   multipath-tools/trunk/kpartx/Makefile
   multipath-tools/trunk/kpartx/byteorder.h
   multipath-tools/trunk/kpartx/devmapper.c
   multipath-tools/trunk/kpartx/devmapper.h
   multipath-tools/trunk/kpartx/dos.c
   multipath-tools/trunk/kpartx/kpartx.c
   multipath-tools/trunk/kpartx/kpartx.h
   multipath-tools/trunk/libcheckers/Makefile
   multipath-tools/trunk/libcheckers/checkers.h
   multipath-tools/trunk/libcheckers/directio.c
   multipath-tools/trunk/libcheckers/emc_clariion.c
   multipath-tools/trunk/libcheckers/hp_sw.c
   multipath-tools/trunk/libcheckers/readsector0.c
   multipath-tools/trunk/libcheckers/tur.c
   multipath-tools/trunk/libmultipath/Makefile
   multipath-tools/trunk/libmultipath/alias.c
   multipath-tools/trunk/libmultipath/blacklist.c
   multipath-tools/trunk/libmultipath/blacklist.h
   multipath-tools/trunk/libmultipath/callout.c
   multipath-tools/trunk/libmultipath/callout.h
   multipath-tools/trunk/libmultipath/config.c
   multipath-tools/trunk/libmultipath/config.h
   multipath-tools/trunk/libmultipath/debug.c
   multipath-tools/trunk/libmultipath/debug.h
   multipath-tools/trunk/libmultipath/defaults.c
   multipath-tools/trunk/libmultipath/defaults.h
   multipath-tools/trunk/libmultipath/devmapper.c
   multipath-tools/trunk/libmultipath/devmapper.h
   multipath-tools/trunk/libmultipath/dict.c
   multipath-tools/trunk/libmultipath/dict.h
   multipath-tools/trunk/libmultipath/discovery.c
   multipath-tools/trunk/libmultipath/discovery.h
   multipath-tools/trunk/libmultipath/dmparser.c
   multipath-tools/trunk/libmultipath/dmparser.h
   multipath-tools/trunk/libmultipath/hwtable.c
   multipath-tools/trunk/libmultipath/log.c
   multipath-tools/trunk/libmultipath/log_pthread.c
   multipath-tools/trunk/libmultipath/parser.c
   multipath-tools/trunk/libmultipath/parser.h
   multipath-tools/trunk/libmultipath/pgpolicies.c
   multipath-tools/trunk/libmultipath/pgpolicies.h
   multipath-tools/trunk/libmultipath/print.c
   multipath-tools/trunk/libmultipath/print.h
   multipath-tools/trunk/libmultipath/propsel.c
   multipath-tools/trunk/libmultipath/propsel.h
   multipath-tools/trunk/libmultipath/structs.c
   multipath-tools/trunk/libmultipath/structs.h
   multipath-tools/trunk/libmultipath/switchgroup.c
   multipath-tools/trunk/libmultipath/uevent.c
   multipath-tools/trunk/libmultipath/uevent.h
   multipath-tools/trunk/libmultipath/uxsock.c
   multipath-tools/trunk/libmultipath/vector.c
   multipath-tools/trunk/multipath-tools.spec.in
   multipath-tools/trunk/multipath.conf.annotated
   multipath-tools/trunk/multipath.conf.synthetic
   multipath-tools/trunk/multipath/Makefile
   multipath-tools/trunk/multipath/main.c
   multipath-tools/trunk/multipath/main.h
   multipath-tools/trunk/multipath/multipath.rules
   multipath-tools/trunk/multipathd/Makefile
   multipath-tools/trunk/multipathd/cli.c
   multipath-tools/trunk/multipathd/cli.h
   multipath-tools/trunk/multipathd/cli_handlers.c
   multipath-tools/trunk/multipathd/cli_handlers.h
   multipath-tools/trunk/multipathd/main.c
   multipath-tools/trunk/multipathd/main.h
   multipath-tools/trunk/multipathd/uxclnt.c
   multipath-tools/trunk/multipathd/uxlsnr.c
   multipath-tools/trunk/path_priority/pp_alua/Makefile
   multipath-tools/trunk/path_priority/pp_balance_units/Makefile
   multipath-tools/trunk/path_priority/pp_emc/Makefile
   multipath-tools/trunk/path_priority/pp_random/Makefile
Log:
Merge /multipath-tools/upstream/current (0.4.7).


Modified: multipath-tools/trunk/ChangeLog
==============================================================================
--- multipath-tools/trunk/ChangeLog	(original)
+++ multipath-tools/trunk/ChangeLog	Mon Mar 13 15:16:41 2006
@@ -1,1068 +1,6 @@
-2005-05-23 multipath-tools-0.4.5
+Change logs are at :
 
-	* [libmultipath] default_prio and prio_callout keyword can be
-	  explicitly set to "none". Suggested by Kiyoshi Ueda, NEC
-	* [path_prio] don't exit pp_balance_units with error when
-	  find_controler() is not successful. It just means no other
-	  path is currently active on this controler.
-	* [path_prio] move balance_units in its own dir
-	* [multipathd] proactively fail_path upon checker up->down
-	  transitions. Suggested by Edward Goggin, EMC
-	* [libmultipath] .priority is clearly an int, not an unsigned
-	  int. /bin/false is now personna non grata as a prio callout.
-	  Kiyoshi Ueda, NEC
-	* [libmultipath] callout.c argv parsing fix. Kiyoshi Ueda,
-	  NEC
-	* [multipathd] check return codes in init_paths(), split out
-	  init_event().
-	* [libmultipath] add find_slot(vec, addr) to vector lib.
-	* [multipath] remove signal sending
-	* [multipathd] use uevent to do paths list housekeeping for
-	  checkers. Remove signal handling.
-	* [libmultipath] add uevent.[ch]
-
-2005-04-23 multipath-tools-0.4.4
-
-	* [path_prio] clarify pp_alua licensing. Stefan Bader, IBM.
-	* [devmap_name] add a target_type filter (suggested by Hannes)
-	  and set DM task device by major:minor rather than parsing
-	  the full map list.
-	* [libmultipath] propagate an error on getprio callout
-	  failures, so that multipath can mark the map as immutable.
-	  Reported by Lars Marowsky-Brée, Suse.
-	* [libmultipath] move push_callout() from dict.c to config.c
-	  Use it in store_hwe() to get in multipathd's ramfs the
-	  callout defined in hwtable.c when no config file is used.
-	  Reported by Lars Marowsky-Brée, Suse.
-	* [checkers] zero sense buffers before use in EMC checker.
-	  Lars Marowsky-Brée, Suse.
-	* [all] pre-release bugfixing effort from Alasdair, Hannes, 
-	  Lars, Benjamin Marzinski
-	* [multipathd] set oom_adj to -17 when kernel permits.
-	  Immune to OOM killer ? agk says : watch out for mem
-	  leaks :/
-	* [multipathd] safety nets from udevd : exit early if
-	  not root, chdir to / to avoid pining a mount.
-	* [multipathd] multipathd could loose events coming from
-	  sighup or DM waitev. Add a pending_event counter to
-	  track that.
-	* [path_prio] add pp_emc from Lars M Bree, Suse.
-	* [path_prio] add pp_alua from Stefan Bader, IBM.
-	* [libmultipath] add config.c:load_config(), which sucks
-	  a big chunk of code out of multipath/main.c.
-	* [libmultipath] don't allocate memory in :
-		* devmapper.c:dm_get_map()
-		* devmapper.c:dm_get_status()
-	* [libmultipath] devinfo() a la carte fetching
-	* [libmultipath] merge keepalived memory audit framework
-	  (Thanks again, M. Cassen). Already found and fixed a
-	  couple of leaks.
-	* [libmultipath] flatten/optimize dm_map_present() and
-	  dm_mapname(). Inspired by Alasdair Kergon, RedHat.
-	* [kpartx] dm_map_name() free before use bugfix. Kiyoshi
-	  Ueda, NEC
-	* [kpartx] add hotplug mode. To enable name the binary
-	  "kpartx.dev". Kiyoshi Ueda, NEC
-	* [multipathd] don't loose events in event waiter thread.
-	  Suggested and prototyped by Edward Goggin, EMC
-	* [libmultipath] add return values to vector manipulation
-	  fonctions. Mem alloc return code audit.
-	* [libmultipath] Use "config->udev_dir + path->dev" as
-	  a path devnode to open instead of mknod'ing for each
-	  one. Fix some DoS issues regarding usage of /tmp in
-	  libmultipath/discovery.c:opennode(). Kill unlinknode()
-	* [multipathd] merged the redhat init script and stop
-	  installing one on "make install"
-	* [libmultipath] fold safe_sprintf.h into util.h
-	* [libmultipath] move blacklist to a real regex matcher
-	  Example config files updated : check yours !!
-	* [multipath] fix path group compare logic to not stop
-	  comparing at first path in each PG.
-	* [multipathd] check if pidfile is a dead remnent of a
-	  crashed daemon. If so, overwrite it. Suggested by
-	  Alasdair Kergon, RedHat. Code heavily based on work
-	  by Andrew Tridgell, Samba Fame.
-	* [build] dropped libdevmapper/ and libsysfs/ from the
-	  package. klibc build is now broken until distributors
-	  provide klibc compiled static libraries in their
-	  respective packages.
-	* [libmultipath] dm_task_no_open_count() before each DM
-	  ioctl. Not doing that is reported to cause deadlocks
-	  in kernel-space. Reported by Edward Goggin, EMC, fix
-	  suggested by Alasdair Kergon, RedHat
-	  Note minimal libdevmapper version bumped up to 1.01.
-	* [multipath] switched to condlog(). "make DEBUG=N" is
-	  deprecated. Debug is spat with "-v3" or more.
-	* [multipathd] "multipathd -vN" cmdline arg to control
-	  daemon verbosity. 0 < N < 4. "make LOGLEVEL=N" is
-	  deprecated.
-	* [libmultipath] provide a common condlog() primitive to
-	  switch lib messages to syslog or stdout depending on
-	  who uses the lib (daemon or tool).
-	* [kpartx] give kpartx a private, slim copy of devmap.[ch]
-	* [multipath] allow wwid in blacklist{} config section.
-	  Kiyoshi Ueda, NEC.
-	* [multipathd] set mode value before use (S_IRWXU). Fixes
-	  RedHat Bugzilla Bug 150665.
-	* [all] add ->fd to "struct path *". remove fd from all
-	  checker context declaration. remove lots of duplicate
-	  logic. Now a fd is opened only once for path. It should
-	  also bring a bit safety in contended memory scenarii
-	* [libcheckers] remove redundant sg_include.h
-	* [libmultipath] merge multipath:dict.[ch] with
-	  multipathd:dict.[ch] into libmultipath/. move config.h
-	  there too, add some helper functions to alloc/free
-	  "struct config *" in a new config.c. Start using a
-	  config in the daemon.
-	* [libmultipath] move dm_geteventnr(), dm_get_maps() and
-	  dm_switchgroup() in devmapper.[ch]
-	* [libmultipath] move path discovery logic in
-	  libmultipath. merge devinfo.[ch] and sysfs_devinfo.[ch]
-	  into discovery.[ch]
-	* [libmultipath] move config.h in libmultipath. Move
-	  find_[mp|hw]e in a new config.c. Move "struct hwtable"
-	  declaration in config.h. Move propsel.[ch] in the
-	  lib too.
-	* [multipathd] use libmultipath:dm_type() instead of
-	  duplacate and bogus devmap discovery code.
-	* [multipathd] asynchronous & non-blocking logger
-	  thread. Implementation split into a generic log
-	  lib and a pthread wrapper for locking and events.
-	  An ipc wrapper could be easily created by
-	  interested parties.
-	* [multipath] add "multipath -l -v2 [devname|devt]"
-	  support in complement to [mapname|wwid]
-	* [kpartx] suppress loop.h private copy. Should fix
-	  the reported build problems
-	* [multipath] do sysfs_get_mnt_path() only one time
-	  and store in a global var.
-	* [multipath] further path discovery optimzation
-	* [multipath] purge superfluous includes in main.c
-	* [libmultipath] introduce a cache file. expiry set
-	  to 5 secondes to covert the hotplug event storms.
-	* [multipath] split get_pathvec_sysfs(). Introduce
-	  get_refwwid() and filter_pathvec()
-
-2005-03-19 multipath-tools-0.4.3
-
-	* [libmultipath] rename find_[mp|hw] to find_[mp|hw]e and
-	  introduce a real find_mp().
-	* [priority] provison for recursive compilation of prio
-	  subdirs, in preparation of merging more signicant
-	  prioritizers. Stephan Bader, IBM
-	* [libmultipath] add a netapp controler to the hwtable
-	* [libmultipath] blacklist() not to discard sda[0-9]*
-	  when sda is blacklisted
-	* [multipath] add a rr_min_io keyword in config file.
-	  Suggested by Igor Feoktistov, NetApp
-	* [multipath] stop trying to avoid running in parallel
-	* [multipath] bump up params size to 1024
-	* [multipathd] put prio callouts in to ramfs. Stephan
-	  Bader, IBM
-	* [multipath] simplify multibus pgpolicy : no need to
-	  copy mp->paths into mp->pg->paths then free source :
-	  just copy the ptr and set source to NULL.
-	* [multipath] sort PG by descending prio value in
-	  group_by_prio. Stephan Bader, IBM
-	* [multipath] fix a bug in group_by_prio that lead to
-	  creation of multiple PG for a single prio value
-	* [multipath] don't store multipaths in a vector anymore :
-	  free the "struct multipath" after usage.
-	* [multipath] multiple optimizations in the exec plan
-	* [multipath] allow "multipath -l -v2 [mapname|wwid]"
-	* [build] rip off klibc and move to klcc, at last.
-	  Good job hpa. multipath-tools now depend on klibc
-	  > 1.0 to build with BUILD=klibc flag.
-	* [multipath] never reload a map if no path is up in the
-	  computed new map
-	* [multipath] don't flush maps with open count != 0
-	* [libmultipath] add "int *dm_get_opencount(char *map)"
-	  to devmapper.c
-	* [multipath] plug leaks and optimize devinfo.c. From
-	  Edward Goggin, EMC
-	* [multipath] fix the multipath.dev hotplug script to not
-	  do kpartx stuff in the same run as multipath stuff.
-	  Igor Feoktistov, NetApp, noted the devmap symlink was
-	  not yet present for kpartx to use.
-	* [devmap_name] accept major:minor synthax
-	* [libmultipath] add "char *dm_mapname(int maj, int min)",
-	  needed to fail paths from checker thread
-	* [libmultipath] move dm_reinstate() in the lib, and add
-	  dm_fail_path()
-	* [multipathd] mark failed path as failed upon DM
-	  event. This should fix the design bug noticed by
-	  Ramesh Caushik, Intel, where the daemon didn't run
-	  multipath when a path went down and up in between 2
-	  checks.
-	* [libmultipath] allow NULL as a pathvec in disassemble_map
-	  as is passed only for memory optimization
-	* [libmultipath] add structs.c to store alloc_*() and
-	  free_*()
-	* [libmultipath] move dmparser.[ch] to the lib.
-	  remove devinfo.[ch] dependency.
-	* [build] fix compilation glitch with BUILD=klibc,
-	  flags to force use of local libs, remove the link
-	  dependency in klibc, try to guess kernel sources
-	  and build dirs. Stefan Bader, IBM
-	* [libmultipath] find_hw matching logic to take str
-	  lengths in account. Noticed by Ramesh Caushik, Intel
-	* [multipath] select_action matching logic to take str 
-	  length in account.
-	* [multipath] lookup mp alias name earlier (in coalesce)
-	  Edward Goggin, EMC, noticed we tried to use it before
-	  it was set up.
-
-2005-01-23 multipath-tools-0.4.2
-
-	* [libmultipath] add symmetrix controler family to the
-	  hwtable. Edward Goggin, EMC
-	* [libmultipath] factorize core structs (path, ...)
-	  and defaults (pidfile, configfile, ...). Convert
-	  callers.
-	* [multipath] fix dmparser to properly fetch non-default
-	  hwhandler. Edward Goggin, EMC
-	* [multipath] fix devt2devname matching 8:1 with 8:10
-	  for example. Edward Goggin, EMC
-	* [multipath] switch_pg upon devmap create or reload
-	  Noticed by Ake.
-	* [libmultipath] move find_hw() the library. Convert
-	  users. Now multipathd understand '*' as a product
-	  string
-	* [multipath] dissaemble_map() fix to avoid to
-	  interpret 'D' as a disable PG (not 'F'). Edward
-	  Goggin, EMC
-	* [multipath] find_path() fix to avoid matching 8:1
-	  with 8:10 for example. Edward Goggin, EMC
-	* [libmultipath] move some sysfs fetching routines
-	  to library, under sysfs_devinfo.[ch]. Convert
-	  callers.
-	* [multipath] fix -v0 : avoids the daemon waiting
-	  for the initial multipath run to complete, which
-	  will never happen because of a flooded pipe
-	* [multipathd] add scsi_id to default binvec
-	* [libmultipath] move hwtable related logic to the
-	  library. Convert multipath and multipathd
-	* [multipath] move first blacklist call down after
-	  setup_default_blist()
-	* [libmultipath] move basename() to the lib. Convert
-	  multipath and multipathd.
-	* [libmultipath] move blacklist related logic to the
-	  library. Convert multipath and multipathd
-	* [multipath] fix bug in the default hardware table
-	  matching logic (Lars M-B, Suse)
-	* [multipath] allow "*" as scsi model string wildcard
-	  (Lars M-B, Suse)
-	* [multipath] provide a macro to fill all hwe fields,
-	  use it to declare Clariion models (Lars M-B, Suse)
-	* [multipath] use DEFAULT_GETUID instead of hardcoded
-	  *and* incorrect "/bin/scsi_id -g -s" (Lars M-B, Suse)
-	* [multipath] kill superfluous suspend before table
-	  reload. The code was unsafe, as spotted by Edward
-	  Goggin (EMC)
-	* [multipath] exit early if device parameter is
-	  blacklisted
-	* [multipath] don't check for prefix in initrd's
-	  multipath.dev : this is the tool responsability to
-	  exit early based on its blacklist.
-	* [multipath] don't signal the daemon in initrd
-	  (Guido Guenther, Debian tracker)
-	* [multipath] better fail to run kpartx in initrd
-	  than crashing the whole system. So don't sleep
-	  waiting for udev to create the DM node. Maybe udev
-	  has made progress I this regard ... (noticed by
-	  Paul Wagland, Debian tracker)
-	* [multipath] don't reinstate when listing, ie list
-	  implies dry_run
-	* [checkers] fix the emc checker (Hergen Lange)
-	* [multipath] node_name fetching shouldn't exit on
-	  error. FC SAN are not the only multipathed context
-	  (noticed by Ramesh Caushik)
-
-2004-12-20 multipath-tools-0.4.1
-
-	* [multipath] bump SERIAL_SIZE to 19
-	* [multipath] add a new group_by_node_name pgpolicy
-	* [multipath] move getopt policy parser to
-	  get_policy_id()
-	* [multipath] remove get_evpd_wwid()
-	* [checkers] fix the wwn_set test in emc checker
-	  (Hergen Lange)
-	* [checkers] treat the emc checker in the name to 
-	  index translator function (Hergen Lange)
-	* [multipath] print to stderr DM unmet requirement
-	  (Guido Guenther)
-	* [multipath] fix realloc return value store not
-	  propagated to caller by merge_word() (Nicola Ranaldo)
-
-2004-12-10 multipath-tools-0.4.0
-
-	* [checkers] forgot to return back to caller the newly
-	  allocated context. Lead to fd leak notably.
-	* [checkers] heavy check logic fix
-	* [checkers] really malloc the checker context size,
-	  not the pointer size (stupidy may kill)
-	* [multipathd] check more sysfs calls return values
-	* [multipathd] search for sysfs mount point only once,
-	  not on each updatepaths() iteration
-	* [multipathd] plug (char *) leak in the daemon
-	* [multipath] change pgcmp logic : we want to reload a
-	  map only if a path is in computed map but not in cur
-	  map (ie accept to load a map if it brings more paths)
-	* [multipath] undust coalesce_paths()
-	* [multipath] don't print unchanged multipath
-	* [multipath] store the action to take in the multipath
-	  struct
-	* [multipath] print mp size with kB, MB, GB or TB units
-	* [multipath] compilation fix for merge_words() (Andy)
-	* [multipath] don't feed the kernel DM maps with paths of
-	  different sizes : DM fails and we end up with an empty
-	  map ... not fun
-	* [multipath] cover a new corner case : path listed in
-	  status string but disappeared from sysfs
-	* [multipath] remove the "-D" command line flag : now
-	  we can pass major:minor directly as last argument, like
-	  device names or device map names. Update multipathd
-	  accordingly.
-	* [multipath] try reinstate again paths after a switchpg
-	* [multipath] reinstate condition change : 
-
-2004-12-05 multipath-tools-0.3.9
-
-	* [multipath] add a "-l" flag to list the current
-	  multipath maps and their status info
-	* [priority] zalloc controler to avoid random path_count
-	  at allocation time
-	* [multipath] add configlet pointers in struct multipath
-	  to avoid searching for an entry over and over again
-	* [multipath] new reinstate policy : on multipath exec,
-	  reinstate all failed paths the checkers report as ready
-	  if they belong to enabled path groups (not disabled, not
-	  active path group)
-	* [multipath] fork a print_mp() out of print_all_mp()
-	* [multipath] introduce PG priority, which is the sum of
-	  its path priorities. Set first_pg in the map string to
-	  the highest prio PG index.
-	* [multipath] assemble maps scaning PG top down now that
-	  PG vector is unsorted
-	* [multipath] move select_*() to propsel.c
-	* [multipath] move devinfo() to devinfo.c
-	* [multipath] move h/b/t/l fetching to sysfs_devinfo()
-	* [multipath] move devt2devname() to devinfo.c so we can
-	  use it from dmparser.c too
-	* [multipath] introduce select_alias() and clarify a bit
-	  of code
-	* [multipath] don't sort PG anymore. We want the map as
-	  static as possible.
-	* [multipath] fix a segfault in apply_format() triggered
-	  when no config file found.
-	* [multipath] kill unused vars all over the place
-	* [multipath] add a struct pathgroup in struct multipath
-	  Store the pathvec in it. We now have a place to store
-	  PG status, etc ...
-	* [multipath] new dmparser.c, with disassemble_map(),
-	  disassemble_status()
-	* [multipath] suppress *selector_args keywords. Merge
-	  in the selector string. Update config file templates.
-
-2004-11-26 multipath-tools-0.3.8
-
-	* [priority] teach multipath to read callout keywords
-	  formatted as /sbin/scsi_id -g -u -s /block/%n
-	  Apply one substitutions out of :
-		* %n : blockdev basename (ie sdb)
-		* %d : blockdev major:minor string (ie 8:16)
-	  update sample config files
-	* [priority] fix find_controler(). Now works, verified
-	  on IBM T200 at OSDL (thanks again, Dave). Add to the
-	  main build process
-	* [multipath] add a controler specific "prio_callout"
-	  keyword. Noticed by Ake
-	* [multipath] normalize the debug ouput
-	* [multipath] add select_getuid(). De-spaghetti
-	  devinfo() thanks to that helper.
-	* [libmultipath] add VECTOR_LAST_SLOT macro.
-	  multipath/dict.h now use it heavily.
-	* [multipath] policies selectors speedup and cleanup
-	  (pgpolicy, features, hwhandler, selector)
-	* [multipath] new "flush" command flag
-	* [libmultipath] add dm_type() and dm_flush_maps()
-	* [multipath] move dm_get_map() to libmultipath
-	* [multipath] rename iopolicy to pgpolicy everywhere.
-	  Dual terminology was getting confusing.
-	* [multipath] assemble_map() to always set next_pg to 1
-	  for now.
-	* [multipath] update config file to show new keywords.
-	  Add an IBM array tested at OSDL.
-	* [multipath] fork select_iopolicy() from setup_map()
-	* [multipath] introduce select_features() and 
-	  select_hwhandler(). Should merge select_* one day ...
-	* [multipath] add features and hardware_handler keywords
-	  and use them in the map setup
-	* [build] make clean really clean. Noticed by Dave Olien,
-	  OSDL
-	* [multipath] group_by_serial bugfix
-	* [multipath] dm_addmap() return value fix. Now multipath
-	  really creates the maps
-	* [multipath] try dm_log_init_verbose() instead of dup()
-	  + close() to silence libdevmapper (Ake at umu)
-	* [libcheckers] remove checkpath() wrapper, obsoleted by
-	  the "fd in context" changes
-	* [multipathd] let pathcheckers allocate their context.
-	  No more over or unneeded allocation.  Suggested by Lars,
-	  Suse
-	* [multipathd] store the pathcheckers fd in their context.
-	  No more open / close on each check. Suggested by Lars,
-	  Suse
-
-2004-11-05 multipath-tools-0.3.7
-
-	* [multipathd] fix off by one memory allocation (Hannes,
-	  Suse)
-	* [multipathd] introduce a default callout handler that
-	  just remembers to put the callout in ramfs, even if the
-	  daemon has no direct use of them. multipath need some
-	  that where forgotten, so parse them and use that default
-	  handler.
-	* [libcheckers] emc_clariion checker update (Lars, Suse)
-	* [build] exit build process on failure (Lars, Suse)
-	* [kpartx] exit early if DM prereq not met
-	* [multipath] exit early if DM prereq not met
-	* [libmultipath] new dm_prereq() fn to check out if all DM
-	  prerequisites are met
-	* [libmultipath] move callout.[ch] function in there.
-	  multipath and multipathd impacted
-	* [libmultipath] move dm_* function in there. kpartx,
-	  multipath are impacted
-	* [priority] pp_balance_lun should use DM_DEVICE_TABLE ioctl
-	  instead of DM_DEVICE_STATUS to find out paths from the
-	  primary path groups.
-	* [klibc] drop in "Stable" version 0.190
-	* [build] add manpages for kpartx and multipathd (Patrick
-	  Caulfield)
-	* [build] use system's sysfs for multipathd linking
-	* [build] make glibc the default build
-	* [build] "make BUILD=klibc" is enough, deprecate the 
-	  "make BUILD=klibc klibc" synthax
-
-2004-10-30 multipath-tools-0.3.6
-
-	* Patrick Caulfield took over debian packaging. Showing
-	  evident expertise, his first wish is to see debian/
-	  disappear. :) So be it.
-	* [libmultipath] add a vector_foreach_slot macro. Still
-	  needs an iterator but saves 1 line per loop occurence and
-	  tame this UPPERCASE MACROS bad taste.
-	* [multipathd] don't load sg anymore on multipathd startup
-	* [multipathd] change killall for kill `cat $PIDFILE` in
-	  init script (Jaime Peñalba & Cesar Solera)
-	* [multipathd] the fork fallback was borked (just exiting)
-	  noticed by Jaime Peñalba & Cesar Solera
-	* [multipathd] try without the FLOATING_STACKS flag. Does
-	  it matter anyway ?
-	* [multipathd] merge clone_platform.h from LTP and cover
-	  the hppa special case.
-	* [multipath] since we will be able to create a devmap with
-	  paths too small, don't rely anymore on the first path's
-	  size blindly : verify the path is up, before assigning its
-	  size to the multipath
-	* [priority] add a path priority fetcher to balance LU accross
-	  controlers based on the controler serial detection. Untested
-	  but provides a good example of what can be done with the
-	  priority framework.
-	* [priority] create subdir and drop a test pp_random
-	* [multipath] add dev_t reporting to print_path() to ease
-	  devmap decoding by humans
-	* [multipath] change default path priority to 1
-	* [multipath] add wits to the sort_by_prio policy, so that
-	  sort_pathvec_by_prio() is now useless. Remove it.
-	* [multipath] invert sort_pg_by_summed_prio sort order :
-	  highest prio leftmost
-	* [libmultipath] add vector_del_slot
-	* revert multipath.rules change : devmap_name still takes
-	  "major minor" and not "major:minor" as argument
-	* Makefile refinement : you can now enter any tool directory
-	  and build from here, deps are solved
-
-2004-10-26 multipath-tools-0.3.5
-
-	* [multipathd] fix broken test for path going up or shaky
-	  that kept executing multipath when it shouldn't
-	* change multipath.dev to exit early when udev' DEVNAME is
-	  a devmap (/dev/dm-*). This avoids a recursion case when
-	  the kernel devmapper keeps removing a map after multipath
-	  configures it.
-	* change multipath.rules to follow the new -D synthax
-	* [multipath] "-D major minor" synthax changed to 
-	  "-D major:minor" to match the sysfs attribute value.
-	  This change removes a few translations in multipath and
-	  multipathd.
-	* [multipath] fix segfault in test if conf->dev is a devmap
-	  (the one forwarded by MikeAnd)
-	* SG_IO ioctl seem to work in lk 2.6.10+, so remove all sg
-	  device knowledge and advertise (here) the new dependency.
-	* [multipath] remove unused do_tur()
-	* [multipath] fix sort_pg_by_summed_prio(), and don't add up
-	  failed path priority
-
-2004-10-26 multipath-tools-0.3.4
-
-	* [multipathd] exec multipath precisely : pass in the path
-	  or the devmap to update. No more full reconfiguration, and
-	  really use the reinstate feature of multipath.
-	* [multipathd] check all paths, not only failed ones. Path
-	  checker now trigger on state change (formerly triggred on
-	  state == UP condition)
-	* [multipathd] incremental updatepaths() instead of scrap /
-	  refresh all logic.
-	* [multipathd] path checkers now take *msg and *context
-	  params. consensus w/ lmb at suse. tur.c modified as example
-	* [multipath] assemble maps in PG vector descending order to
-	  fit the layered policies design
-	* [multipath] stop playing with strings in pgpolicies, as it
-	  uses more memory and looses info for no gain
-	* [multipath] remove lk2.4 scsi ioctl scsi_type remnant
-	* [multipath] layered pgpolicies : (see pgpolicies.c)
-		* group_by_status
-		* group_by_serial | multibus | failover | group_by_prio
-		* sort_pg_by_summed_prio
-	  thus remove duplicated failedpath logic in pgpolicies
-	* [libmultipath] add vector_insert_slot
-	* [checkers] framework for arbitrate checkers return values
-	* [multipathd] scrap yet another reinvented wheel in the 
-	  name of the LOG macro :  learn the existance of setloglevel
-	  and LOG_UPTO macro
-	* glibc make with "make BUILD=glibc", asked by lmb at suse
-
-2004-10-20 multipath-tools-0.3.3
-
-	* [checkers] add the emc_clariion path checker (lmb at Suse)
-	* [multipath] introduce safe_snprintf macro to complement the
-	  safe_sprintf. Needed to cover the sizeof(pointer) cases
-	  pointed by Dave Olien at OSDL
-	* [multipath] move to the common libchecker framework and
-	  activate the selector
-	* [multipath] fix an iopolicy selector bug (initialized lun
-	  iopolicy overrode controler-wide iopolicy)
-	* [multipathd] cleanly separate out the checker selector, as
-	  done with iopolicy selector
-	* [multipathd] move out the checkers into a common libcheckers
-	* [multipath] fix the anti-parallel-exec logic : use a write 
-	  lease for the task. From Dave Olien at osdl.
-	* [multipath] fix reinstate : pass a devt, not a devname
-
-2004-10-16 multipath-tools-0.3.2
-
-	* [multipath] add path reinstate logic :
-		* if a path is given as multipath arg
-		* if the map containing that path already exists
-		* if this map is the same as the that would be
-		  created by this multipath run
-		* THEN reinstate the path
-	  multipathd is is thus unchanged, while now supporting
-	  reinstate
-	* audit and ensafe all sprintf usage
-	* [multipath] fix the annoying \n after each dev_t in
-	  params string reporting
-	* [multipath] print out devmaps in "-v2 -d" mode
-	* [kpartx] bump up the params string size (lmb at suse)
-	* [kpartx] replace sprintf by snprintf (lmb at suse)
-	* [kpartx] initialize some more vars (lmb at suse)
-	* [multipath] mp->pg == NULL safety net before calling
-	  assemble_map() (for Andy who happen to hit the bug)
-	* [multipath] last rampant bug in map CREATE or UPDATE switch
-	  logic due to the device alias feature
-	* [kpartx] zeroe "struct slice all" (lmb at suse)
-
-2004-10-11 multipath-tools-0.3.1
-
-	* [kpartx] move back to getopt, originaly removed from the 
-	  original partx because of lack of implementation in klibc
-	* [kpartx] don't map extended partitions
-	* [kpartx] add a -p command flag to allow admin to force a
-	  delimiting string between disk name and part number. When
-	  specified always use it, when unspecified use 'p' as a delim
-	  when last char of disk name is a digit, NUL otherwise.
-	* [kpartx] clean up
-	* bump klibc to 0.182
-	* one step further : use klibc MCONFIG for all klibc specific
-	  FLAGS definitions, ie massive Makefile.inc cleanup
-	* follow the klibc compilation rules by appending its OPTFLAGS
-	  to multipath-tools' CFLAGS. This corrects the segfaults seen
-	  on i386 where klibc is built with regparm=3 and tools are not
-	* [multipathd] fall back to fork when clone not available
-	  like in Debian Woody
-	* [kpartx] move .start and .size from uint to ulong (Ake)
-	* briefly document system-disk-on-multipath in the FAQ file
-
-2004-10-06 multipath-tools-0.3.0
-
-	* first cut at making scripts to create multipath-aware initrds
-	  those scripts are tested on Debian SID, and must be copied into
-	  /etc/mkinitrd/scripts. it works here.
-	* [multipath] verify presence of the /sys/block/... node before
-	  reading sysfs attributes. Avoids libsysfs and scsi_id stderr
-	  garbage
-	* [multipath] move down the stderr close (Ake Sandgren at umu.se)
-	* [multipath] don't care about 0-sized mp (Ake Sandgren at umu.se)
-	* [multipath] bump mp size field to ulong (Ake Sandgren at umu.se)
-	* [multipath] replace quiet/verbose flags by a verbosity one.
-	  introduce a new verbosity level : 1 == print only devmap names
-	  thus we can feed kpartx with that output
-	* [multipath] update man page to reflect the hotplug.d -> dev.d
-	  transition and replace the obsolete group_by_tur policy by the
-	  forgotten group_by_prio
-	* [multipath] provide a /etc/udev/rules.d/multipath.rules for
-	  multipath devices naming. Cleaner than the previously suggested
-	  rule addition in the main udev.rules
-	* [multipath] move out of hotplug.d to dev.d : kill synchronisation
-	  problems between device node creation and multipath execution.
-	  Incidentally the unfriendly $DEVPATH param become a friendly
-	  $DEVNAME (simply /dev/sdb)
-	* [multipath] rework the iopolicies name-to-id & id-to-name
-	  translations. kills the last compilation warning here too
-	* [kpartx] kill last compilation warnings
-	* bump klibc to 0.181
-	* add the debian/ packaging dir (make deb)
-	* prototype __clone & __clone2
-
-2004-09-24 multipath-tools-0.2.9
-
-	* [multipathd] finally tame the clone compilation glitch on IA64
-	  move from sys_clone to __clone / __clone2
-	* [kpartx] rework from Stephan Bader, IBM :
-		* handle s390x arch
-		* endianness fixes
-		* push the partname string size to handle wwwids
-		* quieten implicit cast warnings
-	* [multipath] add an 'alias' multipath keyword for friendlier device
-	  names. This was "asked" by OSDL' CGL board of secret reviewers
-	* [multipath] last pass with JBOD and parallel SCSI support :
-	  hard-code scsi_id as a fallback when disk strings doesn't match
-	  any hwtable entry
-	* [multipath & multipathd] change the parser to not coalesce
-	  consecutive spaces (Patrick Mansfield)
-	* [multipath] remove the [UN]: output prefix, so that stdout can be
-	  easily fed to a tool like dmsetup
-	* [multipathd] DEBUG=3 logs more readable/usefull
-	* [multipathd] add a multipath_tool config keyword
-	* [multipathd] move to execute_program() like multipath already did
-	* [multipath] don't print the "no path" msg in quiet mode
-	* [multipathd] include linux/unistd.h for _syscall2
-	  definition on RedHat systems. Remove superfluous
-	  asm/unistd.h include
-	* [libsysfs] forked : last version uses mntent, which
-	  klibc doesn't provide. That, plus the fact we use
-	  only 1/3 of the lib, pushed me to freeze the version
-	  and strip all unused stuff.
-	* [multipathd] prepare_namespace() cleanup : no more "multipath"
-	  special casing since we push it to binvec vector, like the other
-	  callouts detected in the config file.
-
-2004-08-13 multipath-tools-0.2.8
-
-	* [multipathd] setsched prio to RT
-	* [multipath] massive include cleanup
-	* [multipath] add a "prio_callout" keyword
-	  first user will be SPC-3 ALUA priority field fetcher
-	  from IBM
-	* [multipath] reenable stdout on some error paths
-	* [build] spilt KERNEL_DIR into KERNEL_SOURCE &
-	  KERNEL_BUILD as per 2.6 and SuSe convention
-	* [klibc] kill warnings due to awk parsing wrong locale in
-	  arch/i386/MCONFIG
-	* [multipath] implement a generic group_by_prio pgpolicy
-	* [multipath] fix the broken failover pgpolicy
-
-2004-07-24 multipath-tools-0.2.7
-
-	* [multipath] args parser moved to getopt
-	  <genanr at emsphone.com>
-	* [multipath] zero conf->hotplugdev at allocation
-	  <genanr at emsphone.com>
-	* [multipath] clean up failed devmap creation attempt
-	* [libs] update to libdevmapper 1.00.19
-	* [multipath] framework for claimed device skipping
-	  still lacks a reliable way to know if the device is
-	  claimed and by who (fs, swap, md, dm, ...). If you
-	  think it is valid to let libdevmapper hit the wall,
-	  please speak up and tell so.
-	* [multipath] shut down stderr when calling into libdm
-	* [multipath] reformat the verbose output
-	* [multipath] framework for path priority handling (ALUA)
-	* [multipath] kill all reference to group_by_tur
-	* [multipath] integrate path state logic into multibus &
-	  failover pgpolicies. This obsoletes the group_by_tur one
-	  which is now the same as multibus.
-	* [multipath] zalloc mp structs to avoid garbage in ->size
-	* bump version requisite for scsi_id to 0.6 to support the new
-	  '-u' flag (s/ /_/ for proper JBOD device map naming)
-	* [multipath] correct the for(;;) limits to accept 1-slot
-	  pathvecs
-	* [multipath] push WWID_SIZE to 64 char (scsi_id w/ JBODs)
-	* [multipath] add a exit_tool() wrapper fn for runfile unlink
-	* [multipath] add a "path_grouping_policy" keyword in the
-	  "defaults" block.
-	* [multipath] add a "getuid_callout" keyword in the
-	  "defaults" block. Now multipath is going to work with JBODs
-	* [multipath] fix segfault when pathvec is empty after
-	  get_pathvec()
-	* move to template based specfile to avoid regular version skew
-
-2004-07-16 multipath-tools-0.2.6
-
-	* [multipathd] implement the system-disk-on-SAN safety net
-	* [multipathd] add exit_daemon() wrapper function
-	* [multipathd] mlockall() all daemon threads
-	* [multipath] fix a bug in the mp_iopolicy_handler that kept
-	  the iopolicy per LUN override from working
-	* [multipath] display the tur bit value in print_path
-	  as requested by SUN
-	* try to open /$udev/reverse/$major:$minor before falling back
-	  to mknod
-	* add "udev_dir" to the defaults block in the config file
-	* merge "daemon" & "device_maps" config blocks into a new
-	  "defaults" block
-	* [multipath] properly comment the config file
-	* [multipath] generalize the dbg() macro usage
-	  Makefile now has a DEBUG flag
-	* [multipath] move to callout based WWID fetching. Default to
-	  scsi_id callout. I merged execute_program from udev for that
-	  (so credit goes to GregKH)
-	* [multipath] get rid of "devnodes in /dev" assumption
-	  ie move to "maj:min" device mapper target synthax
-
-2004-07-10 multipath-tools-0.2.5
-
-	* [multipathd] fix misbehaviour noted by <genanr at emsphone.com>
-	  improper tar directive in Makefile on some systems
-	* [multipathd] fix bug noted by <genanr at emsphone.com>
-	  get_devmaps fills a private vector and forget to pass its
-	  address to caller
-	* [multipath] extend EVPD 0x83 id fetching logic.
-	  Code borrowed from scsi_id (thanks goes to Patrick
-	  Mansfield @IBM) and merged by Hannes Reinecke @SUSE
-	* [multipathd] fix regression noted by <genanr at emsphone.com>
-	  (segfault when no config file)
-
-2004-06-20 multipath-tools-0.2.4
-
-	* [multipathd] break free from system's libsysfs for now
-	  as it is not that common these days
-	* [multipath] introduce per LUN policies in the config
-	  file : path_grouping_policy, path_selector and
-	  path_selector_args are supported.
-	  See updated sample config file.
-	* [multipath] move ->iopolicy to multipath struct (from
-	  path struct)
-	* [multipath] fill the voids left in the config file with
-	  defaults
-	* [multipath] group config & flags in a global struct *
-	* [multipath] fix segfault when no config file (was a 
-	  regression since hwtable vectorisation in 0.2.2)
-	* [multipath] default path selector override in config file
-	* [multipath] don't play with strings in pgpolicies, leave
-	  that to a new assemble_map fn. policies now use vector
-	* [multipathd] compilation fix for gentoo (Franck Denis)
-	* [multipath] strcmp fix (Franck Denis)
-
-2004-06-14 multipath-tools-0.2.3
-
-	* [multipath] group_by_serial try to be smart with LUN
-	  balancing across controlers (for STK / LSI) :
-	  1st multipath : 1st pg made of path through 1st controler
-	  2nd multipath : 1st pg made of path through 2nd controler
-	  3rd multipath : 1st pg made of path through 1st controler
-	  ...
-	* [multipath] drop .pindex[] in struct multipath in favor
-	  of a *paths vector : much cleaner
-	* [multipath] fix group_by_serial pgpolicy broken by
-	  vectorisation in 0.2.2
-	* add a StorageTek array in the sample multipath.conf
-	* [multipathd] strcmp fix from Franck Denis
-	* [multipathd] convert to vector api
-	* [multipathd] add a configfile option for path checking
-	  interval. See sample configfile for synthax.
-
-2004-06-07 multipath-tools-0.2.2
-
-	* [multipath] leave out 2.4 compat code. Is there
-	  interest anyway ?
-	* [multipath] convert all_paths table to vector api.
-	  Rename to pathvec. Get rid of max_devs
-	* [multipath] convert mp table to vector api
-	* convert blacklist to vector api
-	* 2.6.7-rc? adds _user annotations to scsi/sg.h, causing
-	  compilation breakage. Add a "#define _user" in all
-	  sg_include.h (and remove cruft)
-	* merge a real parser (from keepalived) courtesy of 
-	  Alexandre Cassen. Now multipath and multipathd share a
-	  config file. This comes with a nice vector lib.
-	* devnode blacklist moved from hardcoded to config file
-	* Guy Coates noted -O2 CFLAGS lead to multipathd crashes
-	  on IA64. Remove the needless optimisation for now.
-
-2004-06-05 multipath-tools-0.2.1
-
-	* [multipath] add a flag to inihibit the final SIGHUP to
-	  multipathd. Needed to avoid recursion with the correction
-	  below
-	* [multipathd] devmap event now triggers a multipath exec
-	  in addition to the usual updatepaths()
-	* [multipathd] move checkers from sg_io on BLK onto CHR
-	  readsector0 goes from read to sg_read
-	* [multipathd] rely on sysfs for failedpaths enum and no
-	  longer on the device mapper
-	* [multipathd] convert get_lun_strings from ioctl to sysfs
-	  so we can benefit from strings persistency for failed
-	  paths
-	* [multipath] readconfig() to take only 8 char from vendor
-	  string (ake)
-	* [multipath] remove unecessery and wrong getuid == NULL
-	  check from devinfo() (ake)
-	* [multipathd] make readsector0 open path O_DIRECT
-	* [multipathd] sizeof(path) -> sizeof(struct path) (MikeC)
-	* [Makefile] don't try to install and uninstall libs
-	* [devmap_name] kill the wrong trailing '\n'
-	  (Mike Christie)
-	* [kpartx] works with device nodes outside /dev
-	* [kpartx] correctly display the delimiter in partition
-	  name outputs
-
-2004-05-17 multipath-tools-0.2.0
-
-	* change the default klibc by greg's :
-	  corrects the segfaults reported by Ling Hwa Hing
-
-2004-05-16 multipath-tools-0.1.9
-
-	* break free from udev : package klibc and libsysfs
-	* add a spec file and a "make rpm" rule
-	* pensum on klibc changes needed :
-		* mmap.c & fork.c : invert includes
-		* make clean wipes .*.d
-		* auto create the linux symlink
-		* remove tools and specfiles (files and Makefile
-		  targets)
-
-2004-05-15 multipath-tools-0.1.8
-
-	* Makefiles cleanup and factorisation
-	* Compilation fixes for non-ix86 archs, tested on x86_64
-	* strip execs harder for a 10% size reduction
-	* blacklist /dev/fd* and /dev/loop*
-	* dmadm works with sysfs nodes with '!' (cciss for ex)
-
-2004-05-10 multipath-tools-0.1.7
-
-	* bugfixes from	Andy <genanr at emsphone.com> :
-		* read the last line of the config file
-		* add an entry for the 3PARData storage ctlrs
-		* read the last char of vendor and model strings
-
-2004-04-25 multipath-tools-0.1.6
-
-	* add the dmadm WIP tool (read MD superblocks and create
-	  corresponding devmaps when possible)
-	* plug fd leak in TUR path checker
-
-2004-03-25 multipath-tools-0.1.5
-
-	* kpartx to manage the nested bdevs as /dev/cciss/c0d0.
-	  parts are named sysfs style : cciss!c0d0p*
-	* kpartx loop support
-	* kpartx do DM updates if part maps already present
-	* merge kpartx for partitioned multipath support
-	* add get_null_uid to getuid methods. assign it the "0" index
-	  devices with this getuid are thus ignored by multipath.
-	  warning : change /etc/multipath.conf (get_evpd_wwid == 1)
-	* mv all_scsi_ids out of the 2.6 code path, into the 2.4 one
-	* unlink runfile on malloc exit path
-	* update multipath manpage (MikeC)
-
-2004-03-17 multipath-tools-0.1.4
-
-	* multipath clean up
-		* split default hw table in hwtable.h
-		* split grouping policies in pgpolocies.c
-		* pass *mp to setup_map instead of mp[]+index
-	* ensure defhwtable is used if /etc/multipath.conf is buggy
-	* hwtable is not global anymore
-	* unlink the runfile in various error paths
-
-2004-03-13 multipath-tools-0.1.3
-
-	* multipath config tool now has a config file parser
-	  (did I say I make the ugliest parsers ?)
-	* example multipath.conf to put in /etc (manualy)
-
-2004-03-12 multipath-tools-0.1.2
-
-	* detach the per devmap waiter threads
-	* set the thread stack size to lower limits
-	  (VSZ down to 4MB from 85 MB here)
-
-2004-03-06 multipath-tools-0.1.1
-
-	* include dlist.h in multipath main.c (PM Hahn)
-	* typo in hotplug script (PM Hahn)
-	* pass -9 opt to gzip for manpages (PM Hahn)
-
-2004-03-05 multipath-tools-0.1.0
-
-	* add the group_by_tur policy
-	* add the multipathd daemon for pathchecking & DM hot-reconfig
-	* multipath doesn't run twice
-	* massive cleanups, and code restructuring
-	* Avoid Kernel Bug when passing too small a buffer in do_inq()
-	* Sync with 2.6.3-udm4 target synthax (no more PG prio)
-
-2004-02-21 multipath-018
-
-	* From the Debian SID inclusion review (Philipp Matthias Hahn)
-		* use DESTDIR install prefix in the Makefile
-		* add man pages for devmap_name & multipath
-		* correct libsysfs.h includes
-		* fork the hotplug script in its own shell
-	* Sync with the kernel device mapper code as of 2.6.3-udm3
-	  ie. Remove the test interval parameter and its uses
-	* Remove superfluous scsi parameter passed from hotplug
-	* Add the man pages to the [un]install targets
-
-2004-02-17 multipath-017
-
-	* remove the restrictive -f flag.
-	  Introduce a more generic "-m iopolicy" one.
-	* remove useless "int with_sysfs" in env struct 
-
-2004-02-04 multipath-016
-
-	* add a GROUP_BY_SERIAL flag. This should be useful for
-	  controlers that activate they spare paths on simple IO
-	  submition with a penalty. The StorageWorks HW defaults to
-	  this mode, even if the MULTIBUS mode is OK.
-	* remove unused sg_err.c
-	* big restructuring : split devinfo.c from main.c. Export :
-		* void basename (char *, char *);
-		* int get_serial (int, char *);
-		* int get_lun_strings (char *, char *, char *, char *);
-		* int get_evpd_wwid(char *, char *);
-		* long get_disk_size (char *);
-	* stop passing struct env as param
-	* add devmap_name proggy for udev to name devmaps as per their
-	  internal DM name and not only by their sysfs enum name (dm-*)
-	  The corresponding udev.rules line is :
-	  KERNEL="dm-[0-9]*", PROGRAM="/sbin/devmap_name %M %m", \
-	  NAME="%k", SYMLINK="%c"
-	* remove make_dm_node fn & call. Rely on udev for this.
-	* don't rely on the linux symlink in the udev/klibc dir since
-	  udev build doesn't use it anymore. This corrects build breakage
-
-2004-01-19 multipath-013
-
-	* update the DM target synthax to the 2.6.0-udm5 style
-
-2003-12-29 multipath-012
-
-	* check hotplug event refers to a block device; if not exit early
-	* refresh doc
-	* add the uninstall target in Makefile
-
-2003-12-22 multipath-010
-
-	* tweak the install target in Makefile
-	* stop passing fds as argument : this change enable a strict
-	  segregation of ugly 2.4 code
-	* sysfs version of get_lun_strings()
-	* be careful about the return of get_unique_id() since errors 
-	  formerly caught up by if(open()) in the caller fn are now returned
-	  by get_unique_id()
-	* send get_serial() in unused.c
-	* introduce dm-simplecmd for RESUME & SUSPEND requests
-	* split add_map() in setup_map() & dm-addmap()
-	* setup_map() correctly submits "SUSPEND-RELOAD-RESUME or CREATE"
-	  sequences instead of the bogus "RELOAD or CREATE"
-	* don't print .sg_dev if equal to .dev (2.6) in print_path()
-	* since the kernel code handles defective paths, remove all
-	  code to cope with them :
-		* move do_tur() to unused.c
-		* remove .state from path struct
-		* remove .state settings & conditionals
-	* add a cmdline switch to force maps to failover mode,
-	  ie 1 path per priority group
-	* add default policies to the whitelist array (spread io ==
-	  MULTIBUS / io forced to 1 path == FAILOVER)
-	* move get_disk_size() call out of add_map() to coalesce()
-	* comment tricky coalesce() fn
-	* bogus unsused.c file renamed to unused.c
-
-2003-12-20 multipath-010
-
-	* big ChangeLog update
-	* start to give a little control over target params :
-	  introduce cmdline arg -i to control polling interval
-	* cope with hotplug-style calling convention :
-	  ie "multipath scsi $DEVPATH" ... to avoid messing with
-	  online maps not concerned by an event
-	* example hotplug agent to drop in /etc/hotplug.d/scsi
-	* revert the run & resched patch : unless someone proves me
-	  wrong, this was overdesigned
-	* move commented out functions in unused.c
-	* update multipath target params to "udm[23] style"
-	* mp target now supports nr_path == 1, so do we
-	* add gratuitous free()
-	* push version forward
-
-2003-12-15 multipath-009
-
-	* Make the HW-specific get_unique_id switch pretty
-	* Prepare to field-test by whitelisting all known fibre array,
-	  try to fetch WWID from the standard EVPD 0x83 off 8 for everyone
-	* configure the multipath target with round-robin path selector and
-	  conservative default for a start (udm1 style) :
-	  yes it makes this release the firstreally useful one.
-	* temporarily disable map creation for single path device
-	  due to current restrictive defaults in the kernel target.
-	  Sistina should work it out.
-	* correct the strncmp logic in blacklist function.
-	* update the Makefiles to autodetect libgcc.a & gcc includes
-	  "ulibc-style". Factorisation of udevdirs & others niceties
-	* drop a hint about absent /dev/sd? on failed open()
-	* implement a reschedule flag in /var/run.
-	  Last thing the prog do before exit is check if a call to multipath
-	  was done (but canceled by /var/run/multipath.run check) during its
-	  execution. If so restart themain loop.
-	* implement a blacklist of sysfs bdev to not bother with for now
-	  (hd,md, dm, sr, scd, ram, raw).
-	  This avoid sending SG_IO to unappropiate devices.
-	* Adds a /var/run/multipath.run handling to avoid simultaneous runs.
-	* Remove a commented-out "printf"
-	* drop a libdevmapper copy in extras/multipath;
-	  maybe discussions w/Sistina folks will bring a better solution
-	  in the future.
-	* drop a putchar usage in libdevmapper to compile cleanly with klibc
-	* drop another such usage of my own in main.c
-	* massage the Makefile to compile libdevmapper against klibc
-	* use "ld" to produce the binary rather than "gcc -static"
-	* stop being stupid w/ uneeded major, minor & dev in main.c:dm_mk_node()
-	* reverse to creating striped target for now because the multipath
-	  target is more hairy than expected initialy
-	* push the version code to 009 to be in synch w/ udev
-
-2003-11-27 multipath-007
-
-	* removes sg_err.[ch] deps
-	* makes sure the core code play nice with klibc
-	* port the sysfs calls to dlist helpers
-	* links against udev's sysfs (need libsysfs.a & dlist.a)
-	* finally define DM_TARGET as "multipath" as Joe posted the code today
-	  (not tested yet)
-	* push version forward (do you want it in sync with udev version?)
-
-2003-11-19 multipath-006
-
-	* merged in udev-006 tree
-
-2003-09-18 multipath-0.0.1
-
-	* multipath 0.0.1 released.
-	* Initial release.
+- pre-0.4.5
+  http://christophe.varoqui.free.fr/wiki/wakka.php?wiki=ChangeLog
+- post-0.4.5
+  http://www.kernel.org/git/gitweb.cgi?p=linux/storage/multipath-tools/.git;a=log

Modified: multipath-tools/trunk/FAQ
==============================================================================
--- multipath-tools/trunk/FAQ	(original)
+++ multipath-tools/trunk/FAQ	Mon Mar 13 15:16:41 2006
@@ -1,3 +1,5 @@
+More at http://christophe.varoqui.free.fr/wiki/wakka.php?wiki=FAQ
+
 1. How to set up System-on-multipath ?
 ======================================
 

Modified: multipath-tools/trunk/Makefile.inc
==============================================================================
--- multipath-tools/trunk/Makefile.inc	(original)
+++ multipath-tools/trunk/Makefile.inc	Mon Mar 13 15:16:41 2006
@@ -25,9 +25,17 @@
 bindir      = $(exec_prefix)/sbin
 checkersdir = $(TOPDIR)/libcheckers
 multipathdir = $(TOPDIR)/libmultipath
-mandir      = /usr/share/man/man8
+mandir      = $(prefix)/usr/share/man/man8
+rcdir	    = $(prefix)/etc/init.d
 
 GZIP        = /bin/gzip -9 -c
 
 CHECKERSLIB = $(checkersdir)/libcheckers
 MULTIPATHLIB = $(multipathdir)/libmultipath
+
+OPTFLAGS     = -pipe -g -Wall -Wunused -Wstrict-prototypes
+CFLAGS	     = $(OPTFLAGS)
+
+%.o:	%.c
+	$(CC) $(CFLAGS) -c -o $@ $<
+

Modified: multipath-tools/trunk/README
==============================================================================
--- multipath-tools/trunk/README	(original)
+++ multipath-tools/trunk/README	Mon Mar 13 15:16:41 2006
@@ -1,52 +1 @@
-Dependancies :
-==============
-
-These libs have been dropped in the multipath tree :
-  
-o libdevmapper : comes with device-mapper-XXXX.tar.gz
-  See www.sistina.com
-o libsysfs : comes with sysutils or udev
-  See ftp.kernel.org/pub/linux/utils/kernel/hotplug/
-o klibc
-  See ftp.kernel.org/pub/linux/libs/klibc/
-
-External :
-
-o Linux kernel 2.6.10-rc with udm2 patchset (or greater)
-  ftp://sources.redhat.com/pub/dm/
-  
-How it works :
-==============
-
-Get a path list in sysfs.
-
-For each path, a wwid is retrieved by a callout program.
-Only White Listed HW can retrieve this info.
-
-Coalesce the paths according to pluggable policies and store
- the result in mp array.
-
-Feed the maps to the kernel device mapper.
-
-The naming of the corresponding block device is handeld 
-by udev with the help of the devmap_name proggy. It is 
-called by the following rule in /etc/udev/udev.rules :
-
-KERNEL="dm-[0-9]*", PROGRAM="/sbin/devmap_name %M %m", \
-NAME="%k", SYMLINK="%c"
-
-Notes :
-=======
-
-o 2.4.21 version of DM does not like even segment size.
-  if you enconter pbs with this, upgrade DM.
-
-Credits :
-=========
-
-o Heavy cut'n paste from sg_utils. Thanks goes to D. 
-  Gilbert.
-o Light cut'n paste from dmsetup. Thanks Joe Thornber.
-o Greg KH for the nice sysfs API.
-o The klibc guys (Starving Linux Artists :), espacially
-  for their nice Makefiles and specfile
+Things to read

Modified: multipath-tools/trunk/TODO
==============================================================================
--- multipath-tools/trunk/TODO	(original)
+++ multipath-tools/trunk/TODO	Mon Mar 13 15:16:41 2006
@@ -1,3 +1 @@
 Things to do
-
-o activate group dm mesg fn

Modified: multipath-tools/trunk/devmap_name/Makefile
==============================================================================
--- multipath-tools/trunk/devmap_name/Makefile	(original)
+++ multipath-tools/trunk/devmap_name/Makefile	Mon Mar 13 15:16:41 2006
@@ -6,7 +6,6 @@
 include ../Makefile.inc
 
 OBJS = devmap_name.o
-CFLAGS = -pipe -g -Wall -Wunused -Wstrict-prototypes
 
 ifeq ($(strip $(BUILD)),klibc)
 	OBJS += $(libdm)
@@ -24,7 +23,7 @@
 glibc: prepare $(OBJS)
 	$(CC) $(OBJS) -o $(EXEC) $(LDFLAGS)
 	$(GZIP) $(EXEC).8 > $(EXEC).8.gz
-	
+
 klibc: prepare $(OBJS)
 	$(CC) -static -o $(EXEC) $(OBJS)
 	$(GZIP) $(EXEC).8 > $(EXEC).8.gz

Modified: multipath-tools/trunk/devmap_name/devmap_name.c
==============================================================================
--- multipath-tools/trunk/devmap_name/devmap_name.c	(original)
+++ multipath-tools/trunk/devmap_name/devmap_name.c	Mon Mar 13 15:16:41 2006
@@ -1,3 +1,6 @@
+/*
+ * Copyright (c) 2004, 2005 Christophe Varoqui
+ */
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>

Modified: multipath-tools/trunk/kpartx/Makefile
==============================================================================
--- multipath-tools/trunk/kpartx/Makefile	(original)
+++ multipath-tools/trunk/kpartx/Makefile	Mon Mar 13 15:16:41 2006
@@ -6,16 +6,16 @@
 
 include ../Makefile.inc
 
-CFLAGS = -pipe -g -Wall -Wunused -Wstrict-prototypes -I.
+CFLAGS += -I. -D_LARGEFILE64_SOURCE
 
 ifeq ($(strip $(BUILD)),klibc)
 	OBJS = bsd.o dos.o kpartx.o solaris.o unixware.o gpt.o crc32.o \
-	       lopart.o xstrncpy.o devmapper.o \
+	       lopart.o xstrncpy.o devmapper.o dasd.o mac.o \
 	       $(MULTIPATHLIB)-$(BUILD).a $(libdm)
 else
 	LDFLAGS = -ldevmapper
-	OBJS = bsd.o dos.o kpartx.o solaris.o unixware.o \
-	       gpt.o crc32.o lopart.o xstrncpy.o devmapper.o
+	OBJS = bsd.o dos.o kpartx.o solaris.o unixware.o dasd.o \
+	       gpt.o mac.o crc32.o lopart.o xstrncpy.o devmapper.o
 endif
 
 EXEC = kpartx

Modified: multipath-tools/trunk/kpartx/byteorder.h
==============================================================================
--- multipath-tools/trunk/kpartx/byteorder.h	(original)
+++ multipath-tools/trunk/kpartx/byteorder.h	Mon Mar 13 15:16:41 2006
@@ -9,9 +9,15 @@
 #endif
 
 #if BYTE_ORDER == LITTLE_ENDIAN
+#  define le16_to_cpu(x) (x)
+#  define be16_to_cpu(x) bswap_16(x)
 #  define le32_to_cpu(x) (x)
+#  define be32_to_cpu(x) bswap_32(x)
 #elif BYTE_ORDER == BIG_ENDIAN
+#  define le16_to_cpu(x) bswap_16(x)
+#  define be16_to_cpu(x) (x)
 #  define le32_to_cpu(x) bswap_32(x)
+#  define be32_to_cpu(x) (x)
 #else
 #  error unsupported
 #endif

Added: multipath-tools/trunk/kpartx/dasd.c
==============================================================================
--- (empty file)
+++ multipath-tools/trunk/kpartx/dasd.c	Mon Mar 13 15:16:41 2006
@@ -0,0 +1,240 @@
+/*
+ * dasd.c
+ *
+ * IBM DASD partition table handling.
+ *
+ * Mostly taken from drivers/s390/block/dasd.c
+ *
+ * Copyright (c) 2005, Hannes Reinecke, SUSE Linux Products GmbH
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ * USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <inttypes.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <linux/hdreg.h>
+#include <errno.h>
+#include <string.h>
+#include <fcntl.h>
+#include <libdevmapper.h>
+#include "devmapper.h"
+#include "kpartx.h"
+#include "byteorder.h"
+#include "dasd.h"
+
+/*
+ */
+int 
+read_dasd_pt(int fd, struct slice all, struct slice *sp, int ns)
+{
+	int retval = -1;
+	int blocksize, offset, size;
+	long disksize;
+	dasd_information_t info;
+	struct hd_geometry geo;
+	char type[5] = {0,};
+	char name[7] = {0,};
+	unsigned char *label_raw;
+	volume_label_t vlabel;
+	unsigned char *data = NULL;
+	unsigned int blk;
+	int fd_dasd = -1;
+	struct stat sbuf;
+	dev_t dev;
+	char *devname;
+	char pathname[256];
+
+	if (fd < 0) {
+		return -1;
+	}
+
+	if (fstat(fd, &sbuf) == -1) {
+		return -1;
+	}
+
+	devname = dm_mapname(major(sbuf.st_rdev), minor(sbuf.st_rdev));
+
+	if (devname != NULL) {
+		/* We were passed a handle to a dm device.
+		 * Get the first target and operate on that instead.
+		 */
+		if (!(dev = dm_get_first_dep(devname))) {
+			free(devname);
+			return -1;
+		}
+		free(devname);
+
+		if ((unsigned int)major(dev) != 94) {
+			/* Not a DASD */
+			return -1;
+		}
+
+		/*
+		 * Hard to believe, but there's no simple way to translate
+		 * major/minor into an openable device file, so we have
+		 * to create one for ourselves.
+		 */
+		
+		sprintf(pathname, "/dev/.kpartx-node-%u-%u",
+			(unsigned int)major(dev), (unsigned int)minor(dev));
+		if ((fd_dasd = open(pathname, O_RDONLY)) == -1) {
+			/* Devicenode does not exist. Try to create one */
+			if (mknod(pathname, 0600 | S_IFBLK, dev) == -1) {
+				/* Couldn't create a device node */
+				return -1;
+			}
+			fd_dasd = open(pathname, O_RDONLY);
+			/*
+			 * The file will vanish when the last process (we)
+			 * has ceased to access it.
+			 */
+			unlink(pathname);
+		}
+		if (!fd_dasd) {
+			/* Couldn't open the device */
+			return -1;
+		}
+	} else {
+		fd_dasd = fd;
+	}
+
+	if (ioctl(fd_dasd, BIODASDINFO, (unsigned long)&info) != 0) {
+		goto out;
+	}
+
+	if (ioctl(fd_dasd, HDIO_GETGEO, (unsigned long)&geo) != 0) {
+		goto out;
+	}
+	
+	if (ioctl(fd_dasd, BLKGETSIZE, &disksize) != 0)
+		goto out;
+
+	if (ioctl(fd_dasd, BLKSSZGET, &blocksize) != 0)
+		goto out;
+
+	if (blocksize < 512 || blocksize > 4096)
+		goto out;
+
+	/*
+	 * Get volume label, extract name and type.
+	 */
+
+	if (!(data = (unsigned char *)malloc(blocksize)))
+		goto out;
+
+
+	if (lseek(fd_dasd, info.label_block * blocksize, SEEK_SET) == -1)
+		goto out;
+	if (read(fd_dasd, data, blocksize) == -1) {
+		perror("read");
+		goto out;
+	}
+	vtoc_ebcdic_dec(data, type, 4);
+
+	if ((!info.FBA_layout) && (!strcmp(info.type, "ECKD")))
+		label_raw = &data[8];
+	else
+		label_raw = &data[4];
+
+	name[6] = '\0';
+	vtoc_ebcdic_dec(label_raw, name, 6);
+
+	memcpy (&vlabel, data, sizeof(volume_label_t));
+
+	/*
+	 * Three different types: CMS1, VOL1 and LNX1/unlabeled
+	 */
+	if (strncmp(type, "CMS1", 4) == 0) {
+		/*
+		 * VM style CMS1 labeled disk
+		 */
+		int *label = (int *) &vlabel;
+
+		if (label[13] != 0) {
+			/* disk is reserved minidisk */
+			blocksize = label[3];
+			offset = label[13];
+			size = (label[7] - 1)*(blocksize >> 9);
+		} else {
+			offset = (info.label_block + 1) * (blocksize >> 9);
+			size = disksize - offset;
+		}
+		sp[0].start = offset * (blocksize >> 9);
+		sp[0].size = size - offset * (blocksize >> 9);
+		retval = 1;
+	} else if ((strncmp(type, "VOL1", 4) == 0) &&
+		(!info.FBA_layout) && (!strcmp(info.type, "ECKD"))) {
+		/*
+		 * New style VOL1 labeled disk
+		 */
+		int counter;
+
+		/* get block number and read then go through format1 labels */
+		blk = cchhb2blk(&vlabel.vtoc, &geo) + 1;
+		counter = 0;
+		if (lseek(fd_dasd, blk * blocksize, SEEK_SET) == -1)
+			goto out;
+
+		while (read(fd_dasd, data, blocksize) != -1) {
+			format1_label_t f1;
+
+			memcpy(&f1, data, sizeof(format1_label_t));
+
+			/* skip FMT4 / FMT5 / FMT7 labels */
+			if (EBCtoASC[f1.DS1FMTID] == '4'
+			    || EBCtoASC[f1.DS1FMTID] == '5'
+			    || EBCtoASC[f1.DS1FMTID] == '7') {
+			        blk++;
+				continue;
+			}
+
+			/* only FMT1 valid at this point */
+			if (EBCtoASC[f1.DS1FMTID] != '1')
+				break;
+
+			/* OK, we got valid partition data */
+		        offset = cchh2blk(&f1.DS1EXT1.llimit, &geo);
+			size  = cchh2blk(&f1.DS1EXT1.ulimit, &geo) - 
+				offset + geo.sectors;
+			sp[counter].start = offset * (blocksize >> 9);
+			sp[counter].size = size * (blocksize >> 9);
+			counter++;
+			blk++;
+		}
+		retval = counter;
+	} else {
+		/*
+		 * Old style LNX1 or unlabeled disk
+		 */
+		offset = (info.label_block + 1) * (blocksize >> 9);
+		size = disksize - offset;
+		sp[0].start = offset * (blocksize >> 9);
+		sp[0].size = size - offset * (blocksize >> 9);
+		retval = 1;
+	}
+
+ out:
+	if (data != NULL)
+		free(data);
+	if (fd_dasd != -1 && fd_dasd != fd)
+		close(fd_dasd);
+	return retval;
+}

Added: multipath-tools/trunk/kpartx/dasd.h
==============================================================================
--- (empty file)
+++ multipath-tools/trunk/kpartx/dasd.h	Mon Mar 13 15:16:41 2006
@@ -0,0 +1,272 @@
+/*
+ * dasd.h
+ *
+ * IBM DASD partition table handling.
+ *
+ * Mostly taken from drivers/s390/block/dasd.c
+ *
+ * Copyright (c) 2005, Hannes Reinecke, SUSE Linux Products GmbH
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ * USA.
+ */
+
+#ifndef _DASD_H
+#define _DASD_H
+
+typedef struct ttr 
+{
+        uint16_t tt;
+        uint8_t  r;
+} __attribute__ ((packed)) ttr_t;
+
+typedef struct cchhb 
+{
+        uint16_t cc;
+        uint16_t hh;
+        uint8_t b;
+} __attribute__ ((packed)) cchhb_t;
+
+typedef struct cchh 
+{
+        uint16_t cc;
+        uint16_t hh;
+} __attribute__ ((packed)) cchh_t;
+
+typedef struct labeldate 
+{
+        uint8_t  year;
+        uint16_t day;
+} __attribute__ ((packed)) labeldate_t;
+
+
+typedef struct volume_label 
+{
+        char volkey[4];         /* volume key = volume label                 */
+	char vollbl[4];	        /* volume label                              */
+	char volid[6];	        /* volume identifier                         */
+	uint8_t security;	        /* security byte                             */
+	cchhb_t vtoc;           /* VTOC address                              */
+	char res1[5];	        /* reserved                                  */
+        char cisize[4];	        /* CI-size for FBA,...                       */
+                                /* ...blanks for CKD                         */
+	char blkperci[4];       /* no of blocks per CI (FBA), blanks for CKD */
+	char labperci[4];       /* no of labels per CI (FBA), blanks for CKD */
+	char res2[4];	        /* reserved                                  */
+	char lvtoc[14];	        /* owner code for LVTOC                      */
+	char res3[29];	        /* reserved                                  */
+} __attribute__ ((packed)) volume_label_t;
+
+
+typedef struct extent 
+{
+        uint8_t  typeind;          /* extent type indicator                     */
+        uint8_t  seqno;            /* extent sequence number                    */
+        cchh_t llimit;          /* starting point of this extent             */
+        cchh_t ulimit;          /* ending point of this extent               */
+} __attribute__ ((packed)) extent_t;
+
+
+typedef struct dev_const 
+{
+        uint16_t DS4DSCYL;           /* number of logical cyls                  */
+        uint16_t DS4DSTRK;           /* number of tracks in a logical cylinder  */
+        uint16_t DS4DEVTK;           /* device track length                     */
+        uint8_t  DS4DEVI;            /* non-last keyed record overhead          */
+        uint8_t  DS4DEVL;            /* last keyed record overhead              */
+        uint8_t  DS4DEVK;            /* non-keyed record overhead differential  */
+        uint8_t  DS4DEVFG;           /* flag byte                               */
+        uint16_t DS4DEVTL;           /* device tolerance                        */
+        uint8_t  DS4DEVDT;           /* number of DSCB's per track              */
+        uint8_t  DS4DEVDB;           /* number of directory blocks per track    */
+} __attribute__ ((packed)) dev_const_t;
+
+
+typedef struct format1_label 
+{
+	char  DS1DSNAM[44];       /* data set name                           */
+	uint8_t  DS1FMTID;           /* format identifier                       */
+	char  DS1DSSN[6];         /* data set serial number                  */
+	uint16_t DS1VOLSQ;           /* volume sequence number                  */
+	labeldate_t DS1CREDT;     /* creation date: ydd                      */
+	labeldate_t DS1EXPDT;     /* expiration date                         */
+	uint8_t  DS1NOEPV;           /* number of extents on volume             */
+        uint8_t  DS1NOBDB;           /* no. of bytes used in last direction blk */
+	uint8_t  DS1FLAG1;           /* flag 1                                  */
+	char  DS1SYSCD[13];       /* system code                             */
+	labeldate_t DS1REFD;      /* date last referenced                    */
+        uint8_t  DS1SMSFG;           /* system managed storage indicators       */
+        uint8_t  DS1SCXTF;           /* sec. space extension flag byte          */
+        uint16_t DS1SCXTV;           /* secondary space extension value         */
+        uint8_t  DS1DSRG1;           /* data set organisation byte 1            */
+        uint8_t  DS1DSRG2;           /* data set organisation byte 2            */
+  	uint8_t  DS1RECFM;           /* record format                           */
+	uint8_t  DS1OPTCD;           /* option code                             */
+	uint16_t DS1BLKL;            /* block length                            */
+	uint16_t DS1LRECL;           /* record length                           */
+	uint8_t  DS1KEYL;            /* key length                              */
+	uint16_t DS1RKP;             /* relative key position                   */
+	uint8_t  DS1DSIND;           /* data set indicators                     */
+        uint8_t  DS1SCAL1;           /* secondary allocation flag byte          */
+  	char DS1SCAL3[3];         /* secondary allocation quantity           */
+	ttr_t DS1LSTAR;           /* last used track and block on track      */
+	uint16_t DS1TRBAL;           /* space remaining on last used track      */
+        uint16_t res1;               /* reserved                                */
+	extent_t DS1EXT1;         /* first extent description                */
+	extent_t DS1EXT2;         /* second extent description               */
+	extent_t DS1EXT3;         /* third extent description                */
+	cchhb_t DS1PTRDS;         /* possible pointer to f2 or f3 DSCB       */
+} __attribute__ ((packed)) format1_label_t;
+
+
+/*
+ * struct dasd_information_t
+ * represents any data about the data, which is visible to userspace
+ */
+typedef struct dasd_information_t {
+	unsigned int devno;		/* S/390 devno */
+	unsigned int real_devno;	/* for aliases */
+	unsigned int schid;		/* S/390 subchannel identifier */
+	unsigned int cu_type  : 16;	/* from SenseID */
+	unsigned int cu_model :  8;	/* from SenseID */
+	unsigned int dev_type : 16;	/* from SenseID */
+	unsigned int dev_model : 8;	/* from SenseID */
+	unsigned int open_count;
+	unsigned int req_queue_len;
+	unsigned int chanq_len;		/* length of chanq */
+	char type[4];			/* from discipline.name, 'none' for unknown */
+	unsigned int status;		/* current device level */
+	unsigned int label_block;	/* where to find the VOLSER */
+	unsigned int FBA_layout;	/* fixed block size (like AIXVOL) */
+	unsigned int characteristics_size;
+	unsigned int confdata_size;
+	char characteristics[64];	/* from read_device_characteristics */
+	char configuration_data[256];	/* from read_configuration_data */
+} dasd_information_t;
+
+#define DASD_IOCTL_LETTER	 'D'
+#define BIODASDINFO _IOR(DASD_IOCTL_LETTER,1,dasd_information_t)
+#define BLKGETSIZE _IO(0x12,96)
+#define BLKSSZGET _IO(0x12,104)
+
+/*
+ * Only compile this on S/390. Doesn't make any sense
+ * for other architectures.
+ */
+
+static unsigned char EBCtoASC[256] =
+{
+/* 0x00  NUL   SOH   STX   ETX  *SEL    HT  *RNL   DEL */
+	0x00, 0x01, 0x02, 0x03, 0x07, 0x09, 0x07, 0x7F,
+/* 0x08  -GE  -SPS  -RPT    VT    FF    CR    SO    SI */
+	0x07, 0x07, 0x07, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+/* 0x10  DLE   DC1   DC2   DC3  -RES   -NL    BS  -POC
+                                -ENP  ->LF             */
+	0x10, 0x11, 0x12, 0x13, 0x07, 0x0A, 0x08, 0x07,
+/* 0x18  CAN    EM  -UBS  -CU1  -IFS  -IGS  -IRS  -ITB
+                                                  -IUS */
+	0x18, 0x19, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+/* 0x20  -DS  -SOS    FS  -WUS  -BYP    LF   ETB   ESC
+                                -INP                   */
+	0x07, 0x07, 0x1C, 0x07, 0x07, 0x0A, 0x17, 0x1B,
+/* 0x28  -SA  -SFE   -SM  -CSP  -MFA   ENQ   ACK   BEL
+                     -SW                               */
+	0x07, 0x07, 0x07, 0x07, 0x07, 0x05, 0x06, 0x07,
+/* 0x30 ----  ----   SYN   -IR   -PP  -TRN  -NBS   EOT */
+	0x07, 0x07, 0x16, 0x07, 0x07, 0x07, 0x07, 0x04,
+/* 0x38 -SBS   -IT  -RFF  -CU3   DC4   NAK  ----   SUB */
+	0x07, 0x07, 0x07, 0x07, 0x14, 0x15, 0x07, 0x1A,
+/* 0x40   SP   RSP           ä              ----       */
+	0x20, 0xFF, 0x83, 0x84, 0x85, 0xA0, 0x07, 0x86,
+/* 0x48                      .     <     (     +     | */
+	0x87, 0xA4, 0x9B, 0x2E, 0x3C, 0x28, 0x2B, 0x7C,
+/* 0x50    &                                      ---- */
+	0x26, 0x82, 0x88, 0x89, 0x8A, 0xA1, 0x8C, 0x07,
+/* 0x58          ß     !     $     *     )     ;       */
+	0x8D, 0xE1, 0x21, 0x24, 0x2A, 0x29, 0x3B, 0xAA,
+/* 0x60    -     /  ----     Ä  ----  ----  ----       */
+	0x2D, 0x2F, 0x07, 0x8E, 0x07, 0x07, 0x07, 0x8F,
+/* 0x68             ----     ,     %     _     >     ? */
+	0x80, 0xA5, 0x07, 0x2C, 0x25, 0x5F, 0x3E, 0x3F,
+/* 0x70  ---        ----  ----  ----  ----  ----  ---- */
+	0x07, 0x90, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+/* 0x78    *     `     :     #     @     '     =     " */
+	0x70, 0x60, 0x3A, 0x23, 0x40, 0x27, 0x3D, 0x22,
+/* 0x80    *     a     b     c     d     e     f     g */
+	0x07, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
+/* 0x88    h     i              ----  ----  ----       */
+	0x68, 0x69, 0xAE, 0xAF, 0x07, 0x07, 0x07, 0xF1,
+/* 0x90    °     j     k     l     m     n     o     p */
+	0xF8, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70,
+/* 0x98    q     r                    ----        ---- */
+	0x71, 0x72, 0xA6, 0xA7, 0x91, 0x07, 0x92, 0x07,
+/* 0xA0          ~     s     t     u     v     w     x */
+	0xE6, 0x7E, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
+/* 0xA8    y     z              ----  ----  ----  ---- */
+	0x79, 0x7A, 0xAD, 0xAB, 0x07, 0x07, 0x07, 0x07,
+/* 0xB0    ^                    ----     §  ----       */
+	0x5E, 0x9C, 0x9D, 0xFA, 0x07, 0x07, 0x07, 0xAC,
+/* 0xB8       ----     [     ]  ----  ----  ----  ---- */
+	0xAB, 0x07, 0x5B, 0x5D, 0x07, 0x07, 0x07, 0x07,
+/* 0xC0    {     A     B     C     D     E     F     G */
+	0x7B, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
+/* 0xC8    H     I  ----           ö              ---- */
+	0x48, 0x49, 0x07, 0x93, 0x94, 0x95, 0xA2, 0x07,
+/* 0xD0    }     J     K     L     M     N     O     P */
+	0x7D, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50,
+/* 0xD8    Q     R  ----           ü                   */
+	0x51, 0x52, 0x07, 0x96, 0x81, 0x97, 0xA3, 0x98,
+/* 0xE0    \           S     T     U     V     W     X */
+	0x5C, 0xF6, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
+/* 0xE8    Y     Z        ----     Ö  ----  ----  ---- */
+	0x59, 0x5A, 0xFD, 0x07, 0x99, 0x07, 0x07, 0x07,
+/* 0xF0    0     1     2     3     4     5     6     7 */
+	0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+/* 0xF8    8     9  ----  ----     Ü  ----  ----  ---- */
+	0x38, 0x39, 0x07, 0x07, 0x9A, 0x07, 0x07, 0x07
+};
+
+static inline void 
+vtoc_ebcdic_dec (const unsigned char *source, char *target, int l) 
+{
+	int i;
+
+	for (i = 0; i < l; i++) 
+		target[i]=(char)EBCtoASC[(unsigned char)(source[i])];
+}
+
+/*
+ * compute the block number from a 
+ * cyl-cyl-head-head structure
+ */
+static inline int
+cchh2blk (cchh_t *ptr, struct hd_geometry *geo) {
+        return ptr->cc * geo->heads * geo->sectors +
+	       ptr->hh * geo->sectors;
+}
+
+
+/*
+ * compute the block number from a 
+ * cyl-cyl-head-head-block structure
+ */
+static inline int
+cchhb2blk (cchhb_t *ptr, struct hd_geometry *geo) {
+        return ptr->cc * geo->heads * geo->sectors +
+		ptr->hh * geo->sectors +
+		ptr->b;
+}
+
+#endif /* _DASD_H */

Modified: multipath-tools/trunk/kpartx/devmapper.c
==============================================================================
--- multipath-tools/trunk/kpartx/devmapper.c	(original)
+++ multipath-tools/trunk/kpartx/devmapper.c	Mon Mar 13 15:16:41 2006
@@ -1,3 +1,6 @@
+/*
+ * Copyright (c) 2004, 2005 Christophe Varoqui
+ */
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -116,11 +119,12 @@
 }
 
 
-const char *
+char *
 dm_mapname(int major, int minor)
 {
 	struct dm_task *dmt;
-	const char *mapname;
+	char *mapname = NULL;
+	const char *map;
 
 	if (!(dmt = dm_task_create(DM_DEVICE_INFO)))
 		return NULL;
@@ -132,9 +136,45 @@
 	if (!dm_task_run(dmt))
 		goto out;
 
-	mapname = strdup(dm_task_get_name(dmt));
+	map = dm_task_get_name(dmt);
+	if (map && strlen(map))
+		mapname = strdup(map);
+
 out:
 	dm_task_destroy(dmt);
 	return mapname;
 }
 
+/*
+ * dm_get_first_dep
+ *
+ * Return the device number of the first dependend device
+ * for a given target.
+ */
+dev_t dm_get_first_dep(char *devname)
+{
+	struct dm_task *dmt;
+	struct dm_deps *dm_deps;
+	dev_t ret = 0;
+
+	if ((dmt = dm_task_create(DM_DEVICE_DEPS)) == NULL) {
+		return ret;
+	}
+	if (!dm_task_set_name(dmt, devname)) {
+		goto out;
+	}
+	if (!dm_task_run(dmt)) {
+		goto out;
+	}
+	if ((dm_deps = dm_task_get_deps(dmt)) == NULL) {
+		goto out;
+	}
+	if (dm_deps->count > 0) {
+		ret = dm_deps->device[0];
+	}
+out:
+	dm_task_destroy(dmt);
+
+	return ret;
+}
+

Modified: multipath-tools/trunk/kpartx/devmapper.h
==============================================================================
--- multipath-tools/trunk/kpartx/devmapper.h	(original)
+++ multipath-tools/trunk/kpartx/devmapper.h	Mon Mar 13 15:16:41 2006
@@ -2,4 +2,5 @@
 int dm_simplecmd (int, const char *);
 int dm_addmap (int, const char *, const char *, const char *, unsigned long);
 int dm_map_present (char *);
-const char * dm_mapname(int major, int minor);
+char * dm_mapname(int major, int minor);
+dev_t dm_get_first_dep(char *devname);

Modified: multipath-tools/trunk/kpartx/dos.c
==============================================================================
--- multipath-tools/trunk/kpartx/dos.c	(original)
+++ multipath-tools/trunk/kpartx/dos.c	Mon Mar 13 15:16:41 2006
@@ -1,3 +1,9 @@
+/*
+ * Source: copy of util-linux' partx dos.c
+ *
+ * Copyrights of the original file apply 
+ * Copyright (c) 2005 Bastian Blank
+ */
 #include "kpartx.h"
 #include "byteorder.h"
 #include <stdio.h>
@@ -14,15 +20,16 @@
 			struct slice *sp, int ns)
 {
 	struct partition p;
-	unsigned long start, here;
+	unsigned long start, here, next;
 	unsigned char *bp;
 	int loopct = 0;
 	int moretodo = 1;
 	int i, n=0;
 
-	here = start = le32_to_cpu(ep->start_sect);
+	next = start = le32_to_cpu(ep->start_sect);
 
 	while (moretodo) {
+		here = next;
 		moretodo = 0;
 		if (++loopct > 100)
 			return n;
@@ -37,12 +44,11 @@
 		for (i=0; i<2; i++) {
 			memcpy(&p, bp + 0x1be + i * sizeof (p), sizeof (p));
 			if (is_extended(p.sys_type)) {
-				if (p.nr_sects) {
-					here = start + le32_to_cpu(p.start_sect);
+				if (p.nr_sects && !moretodo) {
+					next = start + le32_to_cpu(p.start_sect);
 					moretodo = 1;
 				}
-				else
-					continue;
+				continue;
 			}
 			if (n < ns) {
 				sp[n].start = here + le32_to_cpu(p.start_sect);
@@ -80,9 +86,6 @@
 
 	for (i=0; i<4; i++) {
 		memcpy(&p, bp + 0x1be + i * sizeof (p), sizeof (p));
-	}
-	for (i=0; i<4; i++) {
-		memcpy(&p, bp + 0x1be + i * sizeof (p), sizeof (p));
 		if (is_gpt(p.sys_type))
 			return 0;
 		if (i < ns) {
@@ -93,8 +96,11 @@
 				"dos_partition: too many slices\n");
 			break;
 		}
-		if (is_extended(p.sys_type))
+		if (is_extended(p.sys_type)) {
 			n += read_extended_partition(fd, &p, sp+n, ns-n);
+			/* hide the extended partition itself */
+			sp[i].size = 0;
+		}
 	}
 	return n;
 }

Modified: multipath-tools/trunk/kpartx/kpartx.c
==============================================================================
--- multipath-tools/trunk/kpartx/kpartx.c	(original)
+++ multipath-tools/trunk/kpartx/kpartx.c	Mon Mar 13 15:16:41 2006
@@ -1,4 +1,13 @@
 /*
+ * Source: copy of util-linux' partx partx.c
+ *
+ * Copyrights of the original file applies
+ * Copyright (c) 2004, 2005 Christophe Varoqui
+ * Copyright (c) 2005 Kiyoshi Ueda
+ * Copyright (c) 2005 Lars Soltau
+ */
+
+/*
  * Given a block device and a partition table type,
  * try to parse the partition table, and list the
  * contents. Optionally add or remove partitions.
@@ -68,6 +77,8 @@
 	addpts("bsd", read_bsd_pt);
 	addpts("solaris", read_solaris_pt);
 	addpts("unixware", read_unixware_pt);
+	addpts("dasd", read_dasd_pt);
+	addpts("mac", read_mac_pt);
 }
 
 static char short_opts[] = "ladgvnp:t:";
@@ -455,27 +466,14 @@
 /*
  * sseek: seek to specified sector
  */
-#if !defined (__alpha__) && !defined (__ia64__) && !defined (__x86_64__) \
-	&& !defined (__s390x__)
-#include <linux/unistd.h>       /* _syscall */
-static
-_syscall5(int,  _llseek,  uint,  fd, ulong, hi, ulong, lo,
-	  long long *, res, uint, wh);
-#endif
 
 static int
 sseek(int fd, unsigned int secnr) {
-	long long in, out;
-	in = ((long long) secnr << 9);
+	off64_t in, out;
+	in = ((off64_t) secnr << 9);
 	out = 1;
 
-#if !defined (__alpha__) && !defined (__ia64__) && !defined (__x86_64__) \
-	&& !defined (__s390x__)
-	if (_llseek (fd, in>>32, in & 0xffffffff, &out, SEEK_SET) != 0
-	    || out != in)
-#else
-	if ((out = lseek(fd, in, SEEK_SET)) != in)
-#endif
+	if ((out = lseek64(fd, in, SEEK_SET)) != in)
 	{
 		fprintf(stderr, "llseek error\n");
 		return -1;

Modified: multipath-tools/trunk/kpartx/kpartx.h
==============================================================================
--- multipath-tools/trunk/kpartx/kpartx.h	(original)
+++ multipath-tools/trunk/kpartx/kpartx.h	Mon Mar 13 15:16:41 2006
@@ -31,6 +31,8 @@
 extern ptreader read_solaris_pt;
 extern ptreader read_unixware_pt;
 extern ptreader read_gpt_pt;
+extern ptreader read_dasd_pt;
+extern ptreader read_mac_pt;
 
 char *getblock(int fd, unsigned int secnr);
 

Added: multipath-tools/trunk/kpartx/mac.c
==============================================================================
--- (empty file)
+++ multipath-tools/trunk/kpartx/mac.c	Mon Mar 13 15:16:41 2006
@@ -0,0 +1,47 @@
+#include "kpartx.h"
+#include "byteorder.h"
+#include <stdio.h>
+#include <string.h>
+#include "mac.h"
+
+int
+read_mac_pt(int fd, struct slice all, struct slice *sp, int ns) {
+	struct mac_driver_desc *md;
+        struct mac_partition *part;
+	unsigned secsize;
+	char *data;
+	int blk, blocks_in_map;
+        int n = 0;
+
+	md = (struct mac_driver_desc *) getblock(fd, 0);
+	if (md == NULL)
+		return -1;
+
+	if (be16_to_cpu(md->signature) != MAC_DRIVER_MAGIC)
+		return -1;
+
+	secsize = be16_to_cpu(md->block_size);
+	data = getblock(fd, secsize/512);
+	if (!data)
+		return -1;
+	part = (struct mac_partition *) (data + secsize%512);
+
+	if (be16_to_cpu(part->signature) != MAC_PARTITION_MAGIC)
+		return -1;
+
+	blocks_in_map = be32_to_cpu(part->map_count);
+	for (blk = 1; blk <= blocks_in_map && blk <= ns; ++blk, ++n) {
+		int pos = blk * secsize;
+		data = getblock(fd, pos/512);
+		if (!data)
+			return -1;
+
+		part = (struct mac_partition *) (data + pos%512);
+		if (be16_to_cpu(part->signature) != MAC_PARTITION_MAGIC)
+			break;
+
+		sp[n].start = be32_to_cpu(part->start_block) * (secsize/512);
+		sp[n].size = be32_to_cpu(part->block_count) * (secsize/512);
+	}
+	return n;
+}

Added: multipath-tools/trunk/kpartx/mac.h
==============================================================================
--- (empty file)
+++ multipath-tools/trunk/kpartx/mac.h	Mon Mar 13 15:16:41 2006
@@ -0,0 +1,30 @@
+#ifndef MAC_H
+#define MAC_H
+
+#include <stdint.h>
+
+#define MAC_PARTITION_MAGIC     0x504d
+
+/* type field value for A/UX or other Unix partitions */
+#define APPLE_AUX_TYPE  "Apple_UNIX_SVR2"
+
+struct mac_partition {
+        uint16_t  signature;      /* expected to be MAC_PARTITION_MAGIC */
+        uint16_t  res1;
+        uint32_t  map_count;      /* # blocks in partition map */
+        uint32_t  start_block;    /* absolute starting block # of partition */
+        uint32_t  block_count;    /* number of blocks in partition */
+        /* there is more stuff after this that we don't need */
+};
+
+#define MAC_DRIVER_MAGIC        0x4552
+
+/* Driver descriptor structure, in block 0 */
+struct mac_driver_desc {
+        uint16_t  signature;      /* expected to be MAC_DRIVER_MAGIC */
+        uint16_t  block_size;
+        uint32_t  block_count;
+    /* ... more stuff */
+};
+
+#endif

Modified: multipath-tools/trunk/libcheckers/Makefile
==============================================================================
--- multipath-tools/trunk/libcheckers/Makefile	(original)
+++ multipath-tools/trunk/libcheckers/Makefile	Mon Mar 13 15:16:41 2006
@@ -6,7 +6,7 @@
 
 include ../Makefile.inc
 
-OBJS = readsector0.o tur.o selector.o directio.o emc_clariion.o hp_sw.o
+OBJS = checkers.o readsector0.o tur.o directio.o emc_clariion.o hp_sw.o
 
 all: $(BUILD)
 

Added: multipath-tools/trunk/libcheckers/checkers.c
==============================================================================
--- (empty file)
+++ multipath-tools/trunk/libcheckers/checkers.c	Mon Mar 13 15:16:41 2006
@@ -0,0 +1,131 @@
+#include <stdio.h>
+#include <string.h>
+
+#include "checkers.h"
+
+#include "directio.h"
+#include "tur.h"
+#include "hp_sw.h"
+#include "emc_clariion.h"
+#include "readsector0.h"
+
+static struct checker checkers[] = {
+	{
+		.fd         = 0,
+		.name       = DIRECTIO,
+		.message    = "",
+		.context    = NULL,
+		.check      = directio,
+		.init       = directio_init,
+		.free       = directio_free
+	},
+	{
+		.fd         = 0,
+		.name       = TUR,
+		.message    = "",
+		.context    = NULL,
+		.check      = tur,
+		.init       = tur_init,
+		.free       = tur_free
+	},
+	{
+		.fd         = 0,
+		.name       = HP_SW,
+		.message    = "",
+		.context    = NULL,
+		.check      = hp_sw,
+		.init       = hp_sw_init,
+		.free       = hp_sw_free
+	},
+	{
+		.fd         = 0,
+		.name       = EMC_CLARIION,
+		.message    = "",
+		.context    = NULL,
+		.check      = emc_clariion,
+		.init       = emc_clariion_init,
+		.free       = emc_clariion_free
+	},
+	{
+		.fd         = 0,
+		.name       = READSECTOR0,
+		.message    = "",
+		.context    = NULL,
+		.check      = readsector0,
+		.init       = readsector0_init,
+		.free       = readsector0_free
+	},
+	{0, "", "", NULL, NULL, NULL, NULL},
+};
+
+void checker_set_fd (struct checker * c, int fd)
+{
+	c->fd = fd;
+}
+
+struct checker * checker_lookup (char * name)
+{
+	struct checker * c = &checkers[0];
+	
+	while (c->check) {
+		if (!strncmp(name, c->name, CHECKER_NAME_LEN))
+			return c;
+		c++;
+	}
+	return NULL;
+}
+
+int checker_init (struct checker * c)
+{
+	return c->init(c);
+}
+
+void checker_put (struct checker * c)
+{
+	if (c->free)
+		c->free(c);
+	memset(c, 0x0, sizeof(struct checker));
+}
+
+int checker_check (struct checker * c)
+{
+	int r;
+
+	if (c->fd <= 0) {
+		MSG(c, "no usable fd");
+		return PATH_WILD;
+	}
+	r = c->check(c);
+
+	return r;
+}
+
+int checker_selected (struct checker * c)
+{
+	return (c->check) ? 1 : 0;
+}
+
+char * checker_name (struct checker * c)
+{
+	return c->name;
+}
+
+char * checker_message (struct checker * c)
+{
+	return c->message;
+}
+
+struct checker * checker_default (void)
+{
+	return checker_lookup(DEFAULT_CHECKER);
+}
+
+void checker_get (struct checker * dst, struct checker * src)
+{
+	dst->fd = src->fd;
+	strncpy(dst->name, src->name, CHECKER_NAME_LEN);
+	strncpy(dst->message, src->message, CHECKER_MSG_LEN);
+	dst->check = src->check;
+	dst->init = src->init;
+	dst->free = src->free;
+}

Modified: multipath-tools/trunk/libcheckers/checkers.h
==============================================================================
--- multipath-tools/trunk/libcheckers/checkers.h	(original)
+++ multipath-tools/trunk/libcheckers/checkers.h	Mon Mar 13 15:16:41 2006
@@ -1,30 +1,53 @@
 #ifndef _CHECKERS_H
 #define _CHECKERS_H
 
-#define CHECKER_NAME_SIZE 16
-#define DEVNODE_SIZE 256
-#define MAX_CHECKER_MSG_SIZE 256
-
-enum checkers {
-	CHECKER_UNDEF,
-	TUR,
-	READSECTOR0,
-	DIRECTIO,
-	EMC_CLARIION,
-	HP_SW
+/*
+ * path states
+ */
+#define PATH_WILD	-1
+#define PATH_UNCHECKED	0
+#define PATH_DOWN	1
+#define PATH_UP		2
+#define PATH_SHAKY	3
+#define PATH_GHOST	4
+
+#define DIRECTIO     "directio"
+#define TUR          "tur"
+#define HP_SW        "hp_sw"
+#define EMC_CLARIION "emc_clariion"
+#define READSECTOR0  "readsector0"
+
+#define DEFAULT_CHECKER READSECTOR0
+
+/*
+ * strings lengths
+ */
+#define CHECKER_NAME_LEN 16
+#define CHECKER_MSG_LEN 256
+#define CHECKER_DEV_LEN 256
+
+struct checker {
+	int fd;
+	char name[CHECKER_NAME_LEN];
+	char message[CHECKER_MSG_LEN];       /* comm with callers */
+	void * context;                      /* store for persistent data */
+	int (*check)(struct checker *);
+	int (*init)(struct checker *);       /* to allocate the context */
+	void (*free)(struct checker *);      /* to free the context */
 };
 
-#define MSG(a) if (msg != NULL) \
-		snprintf(msg, MAX_CHECKER_MSG_SIZE, "%s", a);
+#define MSG(c, a) snprintf((c)->message, CHECKER_MSG_LEN, a);
 
-int get_checker_id (char *);
-void *get_checker_addr (int);
-int get_checker_name (char *, int);
-
-int emc_clariion (int fd, char * msg, void ** ctxt);
-int directio (int fd, char * msg, void ** ctxt);
-int readsector0 (int fd, char * msg, void ** ctxt);
-int tur (int fd, char * msg, void ** ctxt);
-int hp_sw (int fd, char * msg, void ** ctxt);
+int checker_init (struct checker *);
+void checker_put (struct checker *);
+void checker_reset (struct checker * c);
+void checker_set_fd (struct checker *, int);
+struct checker * checker_lookup (char *);
+int checker_check (struct checker *);
+int checker_selected (struct checker *);
+char * checker_name (struct checker *);
+char * checker_message (struct checker *);
+struct checker * checker_default (void);
+void checker_get (struct checker *, struct checker *);
 
 #endif /* _CHECKERS_H */

Modified: multipath-tools/trunk/libcheckers/directio.c
==============================================================================
--- multipath-tools/trunk/libcheckers/directio.c	(original)
+++ multipath-tools/trunk/libcheckers/directio.c	Mon Mar 13 15:16:41 2006
@@ -1,3 +1,6 @@
+/*
+ * Copyright (c) 2005 Hannes Reinecke, Suse
+ */
 #define _GNU_SOURCE
 #include <stdio.h>
 #include <stdlib.h>
@@ -10,17 +13,63 @@
 #include <linux/fs.h>
 #include <errno.h>
 
-#include "path_state.h"
 #include "checkers.h"
 
 #define MSG_DIRECTIO_UNKNOWN	"directio checker is not available"
 #define MSG_DIRECTIO_UP		"directio checker reports path is up"
 #define MSG_DIRECTIO_DOWN	"directio checker reports path is down"
 
-struct readsector0_checker_context {
-	void * dummy;
+struct directio_context {
+	int blksize; 
+	unsigned char *buf;
+	unsigned char *ptr;
 };
 
+int directio_init (struct checker * c)
+{
+	unsigned long pgsize = getpagesize();
+	struct directio_context * ct;
+
+	ct = malloc(sizeof(struct directio_context));
+	if (!ct)
+		return 1;
+	c->context = (void *)ct;
+
+	if (ioctl(c->fd, BLKBSZGET, &ct->blksize) < 0) {
+		MSG(c, "cannot get blocksize, set default");
+		ct->blksize = 512;
+	}
+	if (ct->blksize > 4096) {
+		/*
+		 * Sanity check for DASD; BSZGET is broken
+		 */
+		ct->blksize = 4096;
+	}
+	if (!ct->blksize)
+		goto out;
+	ct->buf = (unsigned char *)malloc(ct->blksize + pgsize);
+	if (!ct->buf)
+		goto out;
+	ct->ptr = (unsigned char *)(((unsigned long)ct->buf + pgsize - 1) &
+		  (~(pgsize - 1))); 
+
+	return 0;
+out:
+	free(ct);
+	return 1;
+}
+
+void directio_free (struct checker * c)
+{
+	struct directio_context * ct = (struct directio_context *)c->context;
+
+	if (!ct)
+		return;
+	if (ct->buf)
+		free(ct->buf);
+	free(ct);
+}
+
 static int
 direct_read (int fd, unsigned char * buff, int size)
 {
@@ -65,101 +114,26 @@
 	return retval;
 }
 
-extern int
-directio (int fd, char *msg, void **context)
+int directio (struct checker * c)
 {
-	unsigned char *buf, *ptr;
-	struct readsector0_checker_context * ctxt = NULL;
-	unsigned long pgsize, numsect;
-	int ret, blksize;
-
-	pgsize = getpagesize();
-	
-	/*
-	 * caller passed in a context : use its address
-	 */
-	if (context)
-		ctxt = (struct readsector0_checker_context *) (*context);
-
-	/*
-	 * passed in context is uninitialized or volatile context :
-	 * initialize it
-	 */
-	if (!ctxt) {
-		ctxt = malloc(sizeof(struct readsector0_checker_context));
-		memset(ctxt, 0, sizeof(struct readsector0_checker_context));
-
-		if (!ctxt) {
-			MSG("cannot allocate context");
-			return -1;
-		}
-		if (context)
-			*context = ctxt;
-	}
-	if (fd <= 0) {
-		MSG("no usable fd");
-		ret = -1;
-		goto out;
-	}
-	
-	if (ioctl(fd, BLKGETSIZE, &numsect) < 0) {
-		MSG("cannot get number of sectors, set default");
-		numsect = 0;
-	}
+	int ret;
+	struct directio_context * ct = (struct directio_context *)c->context;
 
-	if (ioctl(fd, BLKBSZGET, &blksize) < 0) {
-		MSG("cannot get blocksize, set default");
-		blksize = 512;
-	}
-
-	if (blksize > 4096) {
-		/*
-		 * Sanity check for DASD; BSZGET is broken
-		 */
-		blksize = 4096;
-	}
-
-	if (!blksize) {
-		/*
-		 * Blocksize is 0, assume we can't write
-		 * to this device.
-		 */
-		MSG(MSG_DIRECTIO_DOWN);
-		ret = PATH_DOWN;
-		goto out;
-	}
-
-	buf = (unsigned char *)malloc(blksize + pgsize);
-	if (!buf){
-		goto out;
-	}
-	ptr = (unsigned char *)(((unsigned long)buf + pgsize - 1) &
-				(~(pgsize - 1))); 
-	ret = direct_read(fd, ptr, blksize);
+	ret = direct_read(c->fd, ct->ptr, ct->blksize);
 
 	switch (ret)
 	{
 	case PATH_UNCHECKED:
-		MSG(MSG_DIRECTIO_UNKNOWN);
+		MSG(c, MSG_DIRECTIO_UNKNOWN);
 		break;
 	case PATH_DOWN:
-		MSG(MSG_DIRECTIO_DOWN);
+		MSG(c, MSG_DIRECTIO_DOWN);
 		break;
 	case PATH_UP:
-		MSG(MSG_DIRECTIO_UP);
+		MSG(c, MSG_DIRECTIO_UP);
 		break;
 	default:
 		break;
 	}
-	free(buf);
-
-out:
-	/*
-	 * caller told us he doesn't want to keep the context :
-	 * free it
-	 */
-	if (!context)
-		free(ctxt);
-
 	return ret;
 }

Added: multipath-tools/trunk/libcheckers/directio.h
==============================================================================
--- (empty file)
+++ multipath-tools/trunk/libcheckers/directio.h	Mon Mar 13 15:16:41 2006
@@ -0,0 +1,8 @@
+#ifndef _DIRECTIO_H
+#define _DIRECTIO_H
+
+int directio (struct checker *);
+int directio_init (struct checker *);
+void directio_free (struct checker *);
+
+#endif /* _DIRECTIO_H */

Modified: multipath-tools/trunk/libcheckers/emc_clariion.c
==============================================================================
--- multipath-tools/trunk/libcheckers/emc_clariion.c	(original)
+++ multipath-tools/trunk/libcheckers/emc_clariion.c	Mon Mar 13 15:16:41 2006
@@ -1,3 +1,6 @@
+/*
+ * Copyright (c) 2004, 2005 Lars Marowsky-Bree
+ */
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -8,7 +11,6 @@
 #include <sys/ioctl.h>
 #include <errno.h>
 
-#include "path_state.h"
 #include "checkers.h"
 
 #include "../libmultipath/sg_include.h"
@@ -18,54 +20,34 @@
 #define HEAVY_CHECK_COUNT       10
 
 struct emc_clariion_checker_context {
-	int run_count;
 	char wwn[16];
 	unsigned wwn_set;
 };
 
-int emc_clariion(int fd, char *msg, void **context)
+int emc_clariion_init (struct checker * c)
+{
+	c->context = malloc(sizeof(struct emc_clariion_checker_context));
+	if (!c->context)
+		return 1;
+	((struct emc_clariion_checker_context *)c->context)->wwn_set = 0;
+	return 0;
+}
+
+void emc_clariion_free (struct checker * c)
+{
+	free(c->context);
+}
+
+int emc_clariion(struct checker * c)
 {
 	unsigned char sense_buffer[256] = { 0, };
 	unsigned char sb[128] = { 0, };
 	unsigned char inqCmdBlk[INQUIRY_CMDLEN] = {INQUIRY_CMD, 1, 0xC0, 0,
 						sizeof(sb), 0};
 	struct sg_io_hdr io_hdr;
-	struct emc_clariion_checker_context * ctxt = NULL;
-	int ret;
-
-	/*
-	 * caller passed in a context : use its address
-	 */
-	if (context)
-		ctxt = (struct emc_clariion_checker_context *) (*context);
-
-	/*
-	 * passed in context is uninitialized or volatile context :
-	 * initialize it
-	 */
-	if (!ctxt) {
-		ctxt = malloc(sizeof(struct emc_clariion_checker_context));
-		memset(ctxt, 0, sizeof(struct emc_clariion_checker_context));
-
-		if (!ctxt) {
-			MSG("cannot allocate context");
-			return -1;
-		}
-		if (context)
-			*context = ctxt;
-	}
-	ctxt->run_count++;
-
-	if ((ctxt->run_count % HEAVY_CHECK_COUNT) == 0) {
-		ctxt->run_count = 0;
-		/* do stuff */
-	}
+	struct emc_clariion_checker_context * ct =
+		(struct emc_clariion_checker_context *)c->context;
 
-	if (fd <= 0) {
-		MSG("no usable fd");
-		ret = -1;
-		goto out;
-	}
 	memset(&io_hdr, 0, sizeof (struct sg_io_hdr));
 	io_hdr.interface_id = 'S';
 	io_hdr.cmd_len = sizeof (inqCmdBlk);
@@ -77,21 +59,18 @@
 	io_hdr.sbp = sb;
 	io_hdr.timeout = 60000;
 	io_hdr.pack_id = 0;
-	if (ioctl(fd, SG_IO, &io_hdr) < 0) {
-		MSG("emc_clariion_checker: sending query command failed");
-		ret = PATH_DOWN;
-		goto out;
+	if (ioctl(c->fd, SG_IO, &io_hdr) < 0) {
+		MSG(c, "emc_clariion_checker: sending query command failed");
+		return PATH_DOWN;
 	}
 	if (io_hdr.info & SG_INFO_OK_MASK) {
-		MSG("emc_clariion_checker: query command indicates error");
-		ret = PATH_DOWN;
-		goto out;
+		MSG(c, "emc_clariion_checker: query command indicates error");
+		return PATH_DOWN;
 	}
 	if (/* Verify the code page - right page & revision */
 	    sense_buffer[1] != 0xc0 || sense_buffer[9] != 0x00) {
-		MSG("emc_clariion_checker: Path unit report page in unknown format");
-		ret = PATH_DOWN;
-		goto out;
+		MSG(c, "emc_clariion_checker: Path unit report page in unknown format");
+		return PATH_DOWN;
 	}
 
 	if ( /* Effective initiator type */
@@ -100,16 +79,14 @@
 		|| (sense_buffer[28] & 0x07) != 0x04
 		/* Arraycommpath should be set to 1 */
 		|| (sense_buffer[30] & 0x04) != 0x04) {
-		MSG("emc_clariion_checker: Path not correctly configured for failover");
-		ret = PATH_DOWN;
-		goto out;
+		MSG(c, "emc_clariion_checker: Path not correctly configured for failover");
+		return PATH_DOWN;
 	}
 
 	if ( /* LUN operations should indicate normal operations */
 		sense_buffer[48] != 0x00) {
-		MSG("emc_clariion_checker: Path not available for normal operations");
-		ret = PATH_SHAKY;
-		goto out;
+		MSG(c, "emc_clariion_checker: Path not available for normal operations");
+		return PATH_SHAKY;
 	}
 
 #if 0
@@ -117,8 +94,7 @@
 	 * _would_ bind the path */
 	if ( /* LUN should at least be bound somewhere */
 		sense_buffer[4] != 0x00) {
-		ret = PATH_UP;
-		goto out;
+		return PATH_UP;
 	}
 #endif	
 	
@@ -127,27 +103,17 @@
 	 * change in between, to protect against the path suddenly
 	 * pointing somewhere else.
 	 */
-	if (context && ctxt->wwn_set) {
-		if (memcmp(ctxt->wwn, &sense_buffer[10], 16) != 0) {
-			MSG("emc_clariion_checker: Logical Unit WWN has changed!");
-			ret = PATH_DOWN;
-			goto out;
+	if (ct->wwn_set) {
+		if (memcmp(ct->wwn, &sense_buffer[10], 16) != 0) {
+			MSG(c, "emc_clariion_checker: Logical Unit WWN has changed!");
+			return PATH_DOWN;
 		}
 	} else {
-		memcpy(ctxt->wwn, &sense_buffer[10], 16);
-		ctxt->wwn_set = 1;
+		memcpy(ct->wwn, &sense_buffer[10], 16);
+		ct->wwn_set = 1;
 	}
 	
 	
-	MSG("emc_clariion_checker: Path healthy");
-        ret = PATH_UP;
-out:
-	/*
-	 * caller told us he doesn't want to keep the context :
-	 * free it
-	 */
-	if (!context)
-		free(ctxt);
-
-	return(ret);
+	MSG(c, "emc_clariion_checker: Path healthy");
+        return PATH_UP;
 }

Added: multipath-tools/trunk/libcheckers/emc_clariion.h
==============================================================================
--- (empty file)
+++ multipath-tools/trunk/libcheckers/emc_clariion.h	Mon Mar 13 15:16:41 2006
@@ -0,0 +1,8 @@
+#ifndef _EMC_CLARIION_H
+#define _EMC_CLARIION_H
+
+int emc_clariion (struct checker *);
+int emc_clariion_init (struct checker *);
+void emc_clariion_free (struct checker *);
+
+#endif /* _EMC_CLARIION_H */

Modified: multipath-tools/trunk/libcheckers/hp_sw.c
==============================================================================
--- multipath-tools/trunk/libcheckers/hp_sw.c	(original)
+++ multipath-tools/trunk/libcheckers/hp_sw.c	Mon Mar 13 15:16:41 2006
@@ -1,3 +1,6 @@
+/*
+ * Copyright (c) 2005 Christophe Varoqui
+ */
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -8,7 +11,6 @@
 #include <sys/ioctl.h>
 #include <errno.h>
 
-#include "path_state.h"
 #include "checkers.h"
 
 #include "../libmultipath/sg_include.h"
@@ -30,9 +32,19 @@
 #define MSG_HP_SW_GHOST	"hp_sw checker reports path is ghost"
 
 struct sw_checker_context {
-	int run_count;
+	void * dummy;
 };
 
+int hp_sw_init (struct checker * c)
+{
+	return 0;
+}
+
+void hp_sw_free (struct checker * c)
+{
+	return;
+}
+
 static int
 do_inq(int sg_fd, int cmddt, int evpd, unsigned int pg_op,
        void *resp, int mx_resp_len, int noisy)
@@ -112,66 +124,19 @@
 }
 
 extern int
-hp_sw (int fd, char *msg, void **context)
+hp_sw (struct checker * c)
 {
 	char buff[MX_ALLOC_LEN];
-	struct sw_checker_context * ctxt = NULL;
-	int ret;
 
-	/*
-	 * caller passed in a context : use its address
-	 */
-	if (context)
-		ctxt = (struct sw_checker_context *) (*context);
-
-	/*
-	 * passed in context is uninitialized or volatile context :
-	 * initialize it
-	 */
-	if (!ctxt) {
-		ctxt = malloc(sizeof(struct sw_checker_context));
-		memset(ctxt, 0, sizeof(struct sw_checker_context));
-
-		if (!ctxt) {
-			MSG("cannot allocate context");
-			return -1;
-		}
-		if (context)
-			*context = ctxt;
+	if (0 != do_inq(c->fd, 0, 1, 0x80, buff, MX_ALLOC_LEN, 0)) {
+		MSG(c, MSG_HP_SW_DOWN);
+		return PATH_DOWN;
 	}
-	ctxt->run_count++;
 
-	if ((ctxt->run_count % HEAVY_CHECK_COUNT) == 0) {
-		ctxt->run_count = 0;
-		/* do stuff */
-	}
-	if (fd <= 0) {
-		MSG("no usable fd");
-		ret = -1;
-		goto out;
-	}
-	
-	if (0 != do_inq(fd, 0, 1, 0x80, buff, MX_ALLOC_LEN, 0)) {
-		MSG(MSG_HP_SW_DOWN);
-		ret = PATH_DOWN;
-		goto out;
-	}
-
-	if (do_tur(fd)) {
-		MSG(MSG_HP_SW_GHOST);
-                ret = PATH_GHOST;
-        } else {
-		MSG(MSG_HP_SW_UP);
-		ret = PATH_UP;
-	}
-
-out:
-	/*
-	 * caller told us he doesn't want to keep the context :
-	 * free it
-	 */
-	if (!context)
-		free(ctxt);
-
-	return(ret);
+	if (do_tur(c->fd)) {
+		MSG(c, MSG_HP_SW_GHOST);
+                return PATH_GHOST;
+        }
+	MSG(c, MSG_HP_SW_UP);
+	return PATH_UP;
 }

Added: multipath-tools/trunk/libcheckers/hp_sw.h
==============================================================================
--- (empty file)
+++ multipath-tools/trunk/libcheckers/hp_sw.h	Mon Mar 13 15:16:41 2006
@@ -0,0 +1,8 @@
+#ifndef _HP_SW_H
+#define _HP_SW_H
+
+int hp_sw (struct checker *);
+int hp_sw_init (struct checker *);
+void hp_sw_free (struct checker *);
+
+#endif /* _HP_SW_H */

Modified: multipath-tools/trunk/libcheckers/readsector0.c
==============================================================================
--- multipath-tools/trunk/libcheckers/readsector0.c	(original)
+++ multipath-tools/trunk/libcheckers/readsector0.c	Mon Mar 13 15:16:41 2006
@@ -1,3 +1,6 @@
+/*
+ * Copyright (c) 2004, 2005 Christophe Varoqui
+ */
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -8,7 +11,6 @@
 #include <sys/ioctl.h>
 #include <errno.h>
 
-#include "path_state.h"
 #include "checkers.h"
 
 #include "../libmultipath/sg_include.h"
@@ -23,6 +25,16 @@
 	void * dummy;
 };
 
+int readsector0_init (struct checker * c)
+{
+	return 0;
+}
+
+void readsector0_free (struct checker * c)
+{
+	return;
+}
+
 static int
 sg_read (int sg_fd, unsigned char * buff)
 {
@@ -83,58 +95,23 @@
 }
 
 extern int
-readsector0 (int fd, char *msg, void **context)
+readsector0 (struct checker * c)
 {
 	unsigned char buf[512];
-	struct readsector0_checker_context * ctxt = NULL;
 	int ret;
 
-	/*
-	 * caller passed in a context : use its address
-	 */
-	if (context)
-		ctxt = (struct readsector0_checker_context *) (*context);
-
-	/*
-	 * passed in context is uninitialized or volatile context :
-	 * initialize it
-	 */
-	if (!ctxt) {
-		ctxt = malloc(sizeof(struct readsector0_checker_context));
-		memset(ctxt, 0, sizeof(struct readsector0_checker_context));
-
-		if (!ctxt) {
-			MSG("cannot allocate context");
-			return -1;
-		}
-		if (context)
-			*context = ctxt;
-	}
-	if (fd <= 0) {
-		MSG("no usable fd");
-		ret = -1;
-		goto out;
-	}
-	ret = sg_read(fd, &buf[0]);
+	ret = sg_read(c->fd, &buf[0]);
 
 	switch (ret)
 	{
 	case PATH_DOWN:
-		MSG(MSG_READSECTOR0_DOWN);
+		MSG(c, MSG_READSECTOR0_DOWN);
 		break;
 	case PATH_UP:
-		MSG(MSG_READSECTOR0_UP);
+		MSG(c, MSG_READSECTOR0_UP);
 		break;
 	default:
 		break;
 	}
-out:
-	/*
-	 * caller told us he doesn't want to keep the context :
-	 * free it
-	 */
-	if (!context)
-		free(ctxt);
-
 	return ret;
 }

Added: multipath-tools/trunk/libcheckers/readsector0.h
==============================================================================
--- (empty file)
+++ multipath-tools/trunk/libcheckers/readsector0.h	Mon Mar 13 15:16:41 2006
@@ -0,0 +1,8 @@
+#ifndef _READSECTOR0_H
+#define _READSECTOR0_H
+
+int readsector0 (struct checker *);
+int readsector0_init (struct checker *);
+void readsector0_free (struct checker *);
+
+#endif /* _READSECTOR0_H */

Modified: multipath-tools/trunk/libcheckers/tur.c
==============================================================================
--- multipath-tools/trunk/libcheckers/tur.c	(original)
+++ multipath-tools/trunk/libcheckers/tur.c	Mon Mar 13 15:16:41 2006
@@ -1,3 +1,8 @@
+/*
+ * Some code borrowed from sg-utils.
+ *
+ * Copyright (c) 2004 Christophe Varoqui
+ */
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -8,7 +13,6 @@
 #include <sys/ioctl.h>
 #include <errno.h>
 
-#include "path_state.h"
 #include "checkers.h"
 
 #include "../libmultipath/sg_include.h"
@@ -20,52 +24,26 @@
 #define MSG_TUR_DOWN	"tur checker reports path is down"
 
 struct tur_checker_context {
-	int run_count;
+	void * dummy;
 };
 
+int tur_init (struct checker * c)
+{
+	return 0;
+}
+
+void tur_free (struct checker * c)
+{
+	return;
+}
 
 extern int
-tur (int fd, char *msg, void **context)
+tur (struct checker * c)
 {
+	struct sg_io_hdr io_hdr;
         unsigned char turCmdBlk[TUR_CMD_LEN] = { 0x00, 0, 0, 0, 0, 0 };
-        struct sg_io_hdr io_hdr;
         unsigned char sense_buffer[32];
-	struct tur_checker_context * ctxt = NULL;
-	int ret;
 
-	/*
-	 * caller passed in a context : use its address
-	 */
-	if (context)
-		ctxt = (struct tur_checker_context *) (*context);
-
-	/*
-	 * passed in context is uninitialized or volatile context :
-	 * initialize it
-	 */
-	if (!ctxt) {
-		ctxt = malloc(sizeof(struct tur_checker_context));
-		memset(ctxt, 0, sizeof(struct tur_checker_context));
-
-		if (!ctxt) {
-			MSG("cannot allocate context");
-			return -1;
-		}
-		if (context)
-			*context = ctxt;
-	}
-	ctxt->run_count++;
-
-	if ((ctxt->run_count % HEAVY_CHECK_COUNT) == 0) {
-		ctxt->run_count = 0;
-		/* do stuff */
-	}
-	if (fd <= 0) {
-		MSG("no usable fd");
-		ret = -1;
-		goto out;
-	}
-	
         memset(&io_hdr, 0, sizeof (struct sg_io_hdr));
         io_hdr.interface_id = 'S';
         io_hdr.cmd_len = sizeof (turCmdBlk);
@@ -75,26 +53,14 @@
         io_hdr.sbp = sense_buffer;
         io_hdr.timeout = 20000;
         io_hdr.pack_id = 0;
-        if (ioctl(fd, SG_IO, &io_hdr) < 0) {
-		MSG(MSG_TUR_DOWN);
-                ret = PATH_DOWN;
-		goto out;
+        if (ioctl(c->fd, SG_IO, &io_hdr) < 0) {
+		MSG(c, MSG_TUR_DOWN);
+                return PATH_DOWN;
         }
         if (io_hdr.info & SG_INFO_OK_MASK) {
-		MSG(MSG_TUR_DOWN);
-                ret = PATH_DOWN;
-		goto out;
+		MSG(c, MSG_TUR_DOWN);
+                return PATH_DOWN;
         }
-	MSG(MSG_TUR_UP);
-        ret = PATH_UP;
-
-out:
-	/*
-	 * caller told us he doesn't want to keep the context :
-	 * free it
-	 */
-	if (!context)
-		free(ctxt);
-
-	return(ret);
+	MSG(c, MSG_TUR_UP);
+        return PATH_UP;
 }

Added: multipath-tools/trunk/libcheckers/tur.h
==============================================================================
--- (empty file)
+++ multipath-tools/trunk/libcheckers/tur.h	Mon Mar 13 15:16:41 2006
@@ -0,0 +1,8 @@
+#ifndef _TUR_H
+#define _TUR_H
+
+int tur (struct checker *);
+int tur_init (struct checker *);
+void tur_free (struct checker *);
+
+#endif /* _TUR_H */

Modified: multipath-tools/trunk/libmultipath/Makefile
==============================================================================
--- multipath-tools/trunk/libmultipath/Makefile	(original)
+++ multipath-tools/trunk/libmultipath/Makefile	Mon Mar 13 15:16:41 2006
@@ -6,16 +6,16 @@
 
 include ../Makefile.inc
 
+CFLAGS = -I$(checkersdir)
+
 OBJS = memory.o parser.o vector.o devmapper.o callout.o \
        hwtable.o blacklist.o util.o dmparser.o config.o \
-       structs.o cache.o discovery.o propsel.o dict.o \
+       structs.o discovery.o propsel.o dict.o \
        pgpolicies.o debug.o regex.o defaults.o uevent.o \
        switchgroup.o uxsock.o print.o alias.o log_pthread.o \
-       log.o
-
-CFLAGS = -pipe -g -Wall -Wunused -Wstrict-prototypes
+       log.o configure.o structs_vec.o
 
-PREVBUILD = $(shell nm debug.o|grep log_safe)
+PREVBUILD = $(shell nm debug.o 2> /dev/null|grep log_safe)
 
 ifeq ($(strip $(DAEMON)),1)
 	CFLAGS += -DDAEMON

Modified: multipath-tools/trunk/libmultipath/alias.c
==============================================================================
--- multipath-tools/trunk/libmultipath/alias.c	(original)
+++ multipath-tools/trunk/libmultipath/alias.c	Mon Mar 13 15:16:41 2006
@@ -1,3 +1,7 @@
+/*
+ * Copyright (c) 2005 Christophe Varoqui
+ * Copyright (c) 2005 Benjamin Marzinski, Redhat
+ */
 #include <stdlib.h>
 #include <sys/types.h>
 #include <sys/stat.h>
@@ -102,7 +106,8 @@
 
 	if (err) {
 		if (errno != EINTR)
-			condlog(0, "Cannot lock bindings file : %s");
+			condlog(0, "Cannot lock bindings file : %s",
+					strerror(errno));
 		else
 			condlog(0, "Bindings file is locked. Giving up.");
 	}

Modified: multipath-tools/trunk/libmultipath/blacklist.c
==============================================================================
--- multipath-tools/trunk/libmultipath/blacklist.c	(original)
+++ multipath-tools/trunk/libmultipath/blacklist.c	Mon Mar 13 15:16:41 2006
@@ -1,60 +1,152 @@
+/*
+ * Copyright (c) 2004, 2005 Christophe Varoqui
+ */
 #include <stdio.h>
 
+#include <checkers.h>
+
 #include "memory.h"
 #include "vector.h"
 #include "util.h"
 #include "debug.h"
-#include "regex.h"
+#include "structs.h"
+#include "config.h"
 #include "blacklist.h"
 
-static int
+extern int
 store_ble (vector blist, char * str)
 {
-	regex_t * ble;
+	struct blentry * ble;
 	
 	if (!str)
 		return 0;
 
-	ble = MALLOC(sizeof(regex_t));
+	if (!blist)
+		goto out;
+
+	ble = MALLOC(sizeof(struct blentry));
 
 	if (!ble)
 		goto out;
 
-	if (regcomp(ble, str, REG_EXTENDED|REG_NOSUB))
+	if (regcomp(&ble->regex, str, REG_EXTENDED|REG_NOSUB))
 		goto out1;
 
 	if (!vector_alloc_slot(blist))
 		goto out1;
 
+	ble->str = str;
 	vector_set_slot(blist, ble);
 	return 0;
 out1:
 	FREE(ble);
 out:
+	FREE(str);
 	return 1;
 }
 
+
+extern int
+alloc_ble_device (vector blist)
+{
+	struct blentry_device * ble = MALLOC(sizeof(struct blentry_device));
+
+	if (!ble || !blist)
+		return 1;
+
+	if (!vector_alloc_slot(blist)) {
+		FREE(ble);
+		return 1;
+	}
+	vector_set_slot(blist, ble);
+	return 0;
+}
+	
+extern int
+set_ble_device (vector blist, char * vendor, char * product)
+{
+	struct blentry_device * ble;
+	
+	if (!blist)
+		return 1;
+
+	ble = VECTOR_SLOT(blist, VECTOR_SIZE(blist) - 1);
+
+	if (!ble)
+		return 1;
+
+	if (vendor) {
+		if (regcomp(&ble->vendor_reg, vendor,
+			    REG_EXTENDED|REG_NOSUB)) {
+			FREE(vendor);
+			return 1;
+		}
+		ble->vendor = vendor;
+	}
+	if (product) {
+		if (regcomp(&ble->product_reg, product,
+			    REG_EXTENDED|REG_NOSUB)) {
+			FREE(product);
+			return 1;
+		}
+		ble->product = product;
+	}
+	return 0;
+}
+
 int
-setup_default_blist (vector blist)
+setup_default_blist (struct config * conf)
 {
-	int r = 0;
+	struct blentry * ble;
+	struct hwentry *hwe;
+	char * str;
+	int i;
 
-	r += store_ble(blist, "^(ram|raw|loop|fd|md|dm-|sr|scd|st)[0-9]*");
-	r += store_ble(blist, "^hd[a-z]");
-	r += store_ble(blist, "^cciss!c[0-9]d[0-9]*");
+	str = STRDUP("^(ram|raw|loop|fd|md|dm-|sr|scd|st)[0-9]*");
+	if (!str)
+		return 1;
+	if (store_ble(conf->blist_devnode, str))
+		return 1;
 
-	return r;
+	str = STRDUP("^hd[a-z]");
+	if (!str)
+		return 1;
+	if (store_ble(conf->blist_devnode, str))
+		return 1;
+	
+	str = STRDUP("^cciss!c[0-9]d[0-9]*");
+	if (!str)
+		return 1;
+	if (store_ble(conf->blist_devnode, str))
+		return 1;
+
+	vector_foreach_slot (conf->hwtable, hwe, i) {
+		if (hwe->bl_product) {
+			if (alloc_ble_device(conf->blist_device))
+				return 1;
+			ble = VECTOR_SLOT(conf->blist_device,
+					  VECTOR_SIZE(conf->blist_device) -1);
+			if (set_ble_device(conf->blist_device,
+					   STRDUP(hwe->vendor),
+					   STRDUP(hwe->bl_product))) {
+				FREE(ble);
+				return 1;
+			}
+		}
+	}
+	
+	return 0;
 }
 
 int
-blacklist (vector blist, char * dev)
+blacklist (vector blist, char * str)
 {
 	int i;
-	regex_t * ble;
+	struct blentry * ble;
 
 	vector_foreach_slot (blist, ble, i) {
-		if (!regexec(ble, dev, 0, NULL, 0)) {
-			condlog(3, "%s blacklisted", dev);
+		if (!regexec(&ble->regex, str, 0, NULL, 0)) {
+			condlog(3, "%s: blacklisted", str);
 			return 1;
 		}
 	}
@@ -62,21 +154,41 @@
 }
 
 int
-store_regex (vector blist, char * regex)
+blacklist_device (vector blist, char * vendor, char * product)
 {
-	if (!blist)
+	int i;
+	struct blentry_device * ble;
+
+	vector_foreach_slot (blist, ble, i) {
+		if (!regexec(&ble->vendor_reg, vendor, 0, NULL, 0) &&
+		    !regexec(&ble->product_reg, product, 0, NULL, 0)) {
+			condlog(3, "%s:%s: blacklisted", vendor, product);
+			return 1;
+		}
+	}
+	return 0;
+}
+
+int
+blacklist_path (struct config * conf, struct path * pp)
+{
+	if (blacklist(conf->blist_devnode, pp->dev))
+		return 1;
+
+	if (blacklist(conf->blist_wwid, pp->wwid))
 		return 1;
 
-	if (!regex)
+	if (pp->vendor_id && pp->product_id &&
+	    blacklist_device(conf->blist_device, pp->vendor_id, pp->product_id))
 		return 1;
 
-	return store_ble(blist, regex);
-}	
+	return 0;
+}
 
 void
 free_blacklist (vector blist)
 {
-	regex_t * ble;
+	struct blentry * ble;
 	int i;
 
 	if (!blist)
@@ -84,10 +196,31 @@
 
 	vector_foreach_slot (blist, ble, i) {
 		if (ble) {
-			regfree(ble);
+			regfree(&ble->regex);
+			FREE(ble->str);
 			FREE(ble);
 		}
 	}
+	vector_free(blist);
+}
 
+void
+free_blacklist_device (vector blist)
+{
+	struct blentry_device * ble;
+	int i;
+
+	if (!blist)
+		return;
+
+	vector_foreach_slot (blist, ble, i) {
+		if (ble) {
+			regfree(&ble->vendor_reg);
+			regfree(&ble->product_reg);
+			FREE(ble->vendor);
+			FREE(ble->product);
+			FREE(ble);
+		}
+	}
 	vector_free(blist);
 }

Modified: multipath-tools/trunk/libmultipath/blacklist.h
==============================================================================
--- multipath-tools/trunk/libmultipath/blacklist.h	(original)
+++ multipath-tools/trunk/libmultipath/blacklist.h	Mon Mar 13 15:16:41 2006
@@ -1,11 +1,28 @@
 #ifndef _BLACKLIST_H
 #define _BLACKLIST_H
 
-#define BLIST_ENTRY_SIZE 255
+#include "regex.h"
 
-int setup_default_blist (vector blist);
-int blacklist (vector blist, char * dev);
-int store_regex (vector blist, char * regex);
-void free_blacklist (vector blist);
+struct blentry {
+	char * str;
+	regex_t regex;
+};
+
+struct blentry_device {
+	char * vendor;
+	char * product;
+	regex_t vendor_reg;
+	regex_t product_reg;
+};
+
+int setup_default_blist (struct config *);
+int alloc_ble_device (vector);
+int blacklist (vector, char *);
+int blacklist_device (vector, char *, char *);
+int blacklist_path (struct config *, struct path *);
+int store_ble (vector, char *);
+int set_ble_device (vector, char *, char *);
+void free_blacklist (vector);
+void free_blacklist_device (vector);
 
 #endif /* _BLACKLIST_H */

Modified: multipath-tools/trunk/libmultipath/callout.c
==============================================================================
--- multipath-tools/trunk/libmultipath/callout.c	(original)
+++ multipath-tools/trunk/libmultipath/callout.c	Mon Mar 13 15:16:41 2006
@@ -1,3 +1,9 @@
+/*
+ * Source: copy of the udev package source file
+ *
+ * Copyrights of the source file apply
+ * Copyright (c) 2004 Christophe Varoqui
+ */
 #include <stdio.h>
 #include <sys/stat.h>
 #include <string.h>
@@ -7,6 +13,12 @@
 #include <sys/wait.h>
 #include <errno.h>
 
+#include <checkers.h>
+
+#include "vector.h"
+#include "structs.h"
+#include "debug.h"
+
 #define PROGRAM_SIZE	100
 #define FIELD_PROGRAM
 
@@ -103,3 +115,79 @@
 	}
 	return retval;
 }
+
+extern int
+apply_format (char * string, char * cmd, struct path * pp)
+{
+	char * pos;
+	char * dst;
+	char * p;
+	int len;
+	int myfree;
+
+	if (!string)
+		return 1;
+
+	if (!cmd)
+		return 1;
+
+	dst = cmd;
+	p = dst;
+	pos = strchr(string, '%');
+	myfree = CALLOUT_MAX_SIZE;
+
+	if (!pos) {
+		strcpy(dst, string);
+		return 0;
+	}
+
+	len = (int) (pos - string) + 1;
+	myfree -= len;
+
+	if (myfree < 2)
+		return 1;
+
+	snprintf(p, len, "%s", string);
+	p += len - 1;
+	pos++;
+
+	switch (*pos) {
+	case 'n':
+		len = strlen(pp->dev) + 1;
+		myfree -= len;
+
+		if (myfree < 2)
+			return 1;
+
+		snprintf(p, len, "%s", pp->dev);
+		p += len - 1;
+		break;
+	case 'd':
+		len = strlen(pp->dev_t) + 1;
+		myfree -= len;
+
+		if (myfree < 2)
+			return 1;
+
+		snprintf(p, len, "%s", pp->dev_t);
+		p += len - 1;
+		break;
+	default:
+		break;
+	}
+	pos++;
+
+	if (!*pos)
+		return 0;
+
+	len = strlen(pos) + 1;
+	myfree -= len;
+
+	if (myfree < 2)
+		return 1;
+
+	snprintf(p, len, "%s", pos);
+	condlog(3, "reformated callout = %s", dst);
+	return 0;
+}
+

Modified: multipath-tools/trunk/libmultipath/callout.h
==============================================================================
--- multipath-tools/trunk/libmultipath/callout.h	(original)
+++ multipath-tools/trunk/libmultipath/callout.h	Mon Mar 13 15:16:41 2006
@@ -1 +1,7 @@
+#ifndef _CALLOUT_H
+#define _CALLOUT_H
+
 int execute_program(char *, char *, int);
+int apply_format (char *, char *, struct path *);
+
+#endif /* _CALLOUT_H */

Modified: multipath-tools/trunk/libmultipath/config.c
==============================================================================
--- multipath-tools/trunk/libmultipath/config.c	(original)
+++ multipath-tools/trunk/libmultipath/config.c	Mon Mar 13 15:16:41 2006
@@ -1,7 +1,13 @@
+/*
+ * Copyright (c) 2004, 2005 Christophe Varoqui
+ * Copyright (c) 2005 Benjamin Marzinski, Redhat
+ * Copyright (c) 2005 Edward Goggin, EMC
+ */
 #include <stdio.h>
 #include <string.h>
 
-#include "regex.h"
+#include <checkers.h>
+
 #include "memory.h"
 #include "util.h"
 #include "debug.h"
@@ -9,11 +15,10 @@
 #include "dict.h"
 #include "hwtable.h"
 #include "vector.h"
+#include "structs.h"
+#include "config.h"
 #include "blacklist.h"
 #include "defaults.h"
-#include "config.h"
-
-#include "../libcheckers/checkers.h"
 
 struct hwentry *
 find_hwe (vector hwtable, char * vendor, char * product)
@@ -101,6 +106,9 @@
 	if (hwe->hwhandler)
 		FREE(hwe->hwhandler);
 
+	if (hwe->bl_product)
+		FREE(hwe->bl_product);
+
 	FREE(hwe);
 }
 
@@ -208,114 +216,47 @@
 }
 
 int
-store_hwe (vector hwtable, char * vendor, char * product, int pgp,
-	   char * getuid)
+store_hwe (vector hwtable, struct hwentry * dhwe)
 {
 	struct hwentry * hwe;
 
-	if (dup_hwe(hwtable, vendor, product))
+	if (dup_hwe(hwtable, dhwe->vendor, dhwe->product))
 		return 0;
-
-	hwe = alloc_hwe();
-
-	if (!hwe)
+	
+	if (!(hwe = alloc_hwe()))
 		return 1;
 
-	hwe->vendor = set_param_str(vendor);
-
-	if (!hwe->vendor)
+	if (!dhwe->vendor || !(hwe->vendor = set_param_str(dhwe->vendor)))
 		goto out;
 	
-	hwe->product = set_param_str(product);
-
-	if (!hwe->product)
+	if (!dhwe->product || !(hwe->product = set_param_str(dhwe->product)))
 		goto out;
 	
-	if (pgp)
-		hwe->pgpolicy = pgp;
-
-	if (getuid)
-		hwe->getuid = set_param_str(getuid);
-	else
-		hwe->getuid = set_default(DEFAULT_GETUID);
-
-	if (!hwe->getuid)
+	if (dhwe->getuid && !(hwe->getuid = set_param_str(dhwe->getuid)))
 		goto out;
-	
-	if (!vector_alloc_slot(hwtable))
-		goto out;
-
-	vector_set_slot(hwtable, hwe);
-	return 0;
-out:
-	free_hwe(hwe);
-	return 1;
-}
 
-int
-store_hwe_ext (vector hwtable, char * vendor, char * product, int pgp,
-	   char * getuid, char * getprio, char * hwhandler,
-	   char * features, char * checker, int pgfailback)
-{
-	struct hwentry * hwe;
-
-	if (dup_hwe(hwtable, vendor, product))
-		return 0;
-	
-	hwe = alloc_hwe();
-
-	if (!hwe)
-		return 1;
-
-	hwe->vendor = set_param_str(vendor);
-
-	if (!hwe->vendor)
+	if (dhwe->getprio && !(hwe->getprio = set_param_str(dhwe->getprio)))
 		goto out;
-	
-	hwe->product = set_param_str(product);
-
-	if (!hwe->product)
+				
+	if (dhwe->features && !(hwe->features = set_param_str(dhwe->features)))
 		goto out;
 	
-	if (pgp)
-		hwe->pgpolicy = pgp;
-
-	if (getuid)
-		hwe->getuid = set_param_str(getuid);
-	else
-		hwe->getuid = set_default(DEFAULT_GETUID);
-
-	if (!hwe->getuid)
+	if (dhwe->hwhandler && !(hwe->hwhandler = set_param_str(dhwe->hwhandler)))
 		goto out;
-	
-	if (getprio)
-		hwe->getprio = set_param_str(getprio);
-	else
-		hwe->getprio = NULL;
-
-	if (hwhandler)	
-		hwe->hwhandler = set_param_str(hwhandler);
-	else
-		hwe->hwhandler = set_default(DEFAULT_HWHANDLER);
 
-	if (!hwe->hwhandler)
+	if (dhwe->selector && !(hwe->selector = set_param_str(dhwe->selector)))
 		goto out;
+				
+	hwe->pgpolicy = dhwe->pgpolicy;
+	hwe->pgfailback = dhwe->pgfailback;
+	hwe->rr_weight = dhwe->rr_weight;
+	hwe->no_path_retry = dhwe->no_path_retry;
+	hwe->minio = dhwe->minio;
+	hwe->checker = dhwe->checker;
 
-	if (features)
-		hwe->features = set_param_str(features);
-	else
-		hwe->features = set_default(DEFAULT_FEATURES);
-
-	if (!hwe->features)
+	if (dhwe->bl_product && !(hwe->bl_product = set_param_str(dhwe->bl_product)))
 		goto out;
 
-	if (checker)
-		hwe->checker_index = get_checker_id(checker);
-	else
-		hwe->checker_index = get_checker_id(DEFAULT_CHECKER);
-
-	hwe->pgfailback = pgfailback;
-
 	if (!vector_alloc_slot(hwtable))
 		goto out;
 
@@ -347,19 +288,21 @@
 	if (conf->selector)
 		FREE(conf->selector);
 
-	if (conf->default_getuid)
-		FREE(conf->default_getuid);
+	if (conf->getuid)
+		FREE(conf->getuid);
 
-	if (conf->default_getprio)
-		FREE(conf->default_getprio);
+	if (conf->getprio)
+		FREE(conf->getprio);
 
 	if (conf->features)
 		FREE(conf->features);
 
-	if (conf->default_hwhandler)
-		FREE(conf->default_hwhandler);
+	if (conf->hwhandler)
+		FREE(conf->hwhandler);
 
-	free_blacklist(conf->blist);
+	free_blacklist(conf->blist_devnode);
+	free_blacklist(conf->blist_wwid);
+	free_blacklist_device(conf->blist_device);
 	free_mptable(conf->mptable);
 	free_hwtable(conf->hwtable);
 
@@ -408,15 +351,27 @@
 	if (setup_default_hwtable(conf->hwtable))
 		goto out;
 
-	if (conf->blist == NULL) {
-		conf->blist = vector_alloc();
+	if (conf->blist_devnode == NULL) {
+		conf->blist_devnode = vector_alloc();
 		
-		if (!conf->blist)
+		if (!conf->blist_devnode)
 			goto out;
+	}
+	if (conf->blist_wwid == NULL) {
+		conf->blist_wwid = vector_alloc();
+		
+		if (!conf->blist_wwid)
+			goto out;
+	}
+	if (conf->blist_device == NULL) {
+		conf->blist_device = vector_alloc();
 		
-		if (setup_default_blist(conf->blist))
+		if (!conf->blist_device)
 			goto out;
 	}
+	if (setup_default_blist(conf))
+		goto out;
+
 	if (conf->mptable == NULL) {
 		conf->mptable = vector_alloc();
 
@@ -429,22 +384,22 @@
 	if (conf->udev_dir == NULL)
 		conf->udev_dir = set_default(DEFAULT_UDEVDIR);
 
-	if (conf->default_getuid == NULL)
-		conf->default_getuid = set_default(DEFAULT_GETUID);
+	if (conf->getuid == NULL)
+		conf->getuid = set_default(DEFAULT_GETUID);
 
 	if (conf->features == NULL)
 		conf->features = set_default(DEFAULT_FEATURES);
 
-	if (conf->default_hwhandler == NULL)
-		conf->default_hwhandler = set_default(DEFAULT_HWHANDLER);
+	if (conf->hwhandler == NULL)
+		conf->hwhandler = set_default(DEFAULT_HWHANDLER);
 
 	if (!conf->selector  || !conf->udev_dir         ||
-	    !conf->default_getuid    || !conf->features ||
-	    !conf->default_hwhandler)
+	    !conf->getuid    || !conf->features ||
+	    !conf->hwhandler)
 		goto out;
 
-	if (!conf->default_checker_index)
-		conf->default_checker_index = READSECTOR0;
+	if (!conf->checker)
+		conf->checker = checker_lookup(DEFAULT_CHECKER);
 
 	return 0;
 out:

Modified: multipath-tools/trunk/libmultipath/config.h
==============================================================================
--- multipath-tools/trunk/libmultipath/config.h	(original)
+++ multipath-tools/trunk/libmultipath/config.h	Mon Mar 13 15:16:41 2006
@@ -1,10 +1,6 @@
 #ifndef _CONFIG_H
 #define _CONFIG_H
 
-#ifndef _VECTOR_H
-#include "vector.h"
-#endif
-
 enum devtypes {
 	DEV_NONE,
 	DEV_DEVT,
@@ -13,33 +9,35 @@
 };
 
 struct hwentry {
-	int selector_args;
-	int pgpolicy;
-	int checker_index;
-	int pgfailback;
-	int rr_weight;
-	int no_path_retry;
-
 	char * vendor;
 	char * product;
-	char * selector;
 	char * getuid;
 	char * getprio;
 	char * features;
 	char * hwhandler;
-};
+	char * selector;
+	char * checker_name;
 
-struct mpentry {
-	int selector_args;
 	int pgpolicy;
 	int pgfailback;
 	int rr_weight;
 	int no_path_retry;
+	int minio;
+	struct checker * checker;
+	char * bl_product;
+};
 
+struct mpentry {
 	char * wwid;
-	char * selector;
-	char * getuid;
 	char * alias;
+	char * getuid;
+	char * selector;
+
+	int pgpolicy;
+	int pgfailback;
+	int rr_weight;
+	int no_path_retry;
+	int minio;
 };
 
 struct config {
@@ -48,9 +46,8 @@
 	int list;
 	int pgpolicy_flag;
 	int with_sysfs;
-	int selector_args;
-	int default_pgpolicy;
-	int default_checker_index;
+	int pgpolicy;
+	struct checker * checker;
 	int dev_type;
 	int minio;
 	int checkint;
@@ -64,15 +61,18 @@
 	char * dev;
 	char * udev_dir;
 	char * selector;
-	char * default_getuid;
-	char * default_getprio;
+	char * getuid;
+	char * getprio;
 	char * features;
-	char * default_hwhandler;
+	char * hwhandler;
 	char * bindings_file;
 
 	vector mptable;
 	vector hwtable;
-	vector blist;
+
+	vector blist_devnode;
+	vector blist_wwid;
+	vector blist_device;
 };
 
 struct config * conf;
@@ -88,11 +88,7 @@
 void free_mpe (struct mpentry * mpe);
 void free_mptable (vector mptable);
 
-int store_hwe (vector hwtable, char * vendor, char * product, int pgp,
-		char * getuid);
-int store_hwe_ext (vector hwtable, char * vendor, char * product, int pgp,
-		char * getuid, char * getprio, char * hwhandler,
-		char * features, char * checker, int pgfailback);
+int store_hwe (vector hwtable, struct hwentry *);
 
 int load_config (char * file);
 struct config * alloc_config (void);

Added: multipath-tools/trunk/libmultipath/configure.c
==============================================================================
--- (empty file)
+++ multipath-tools/trunk/libmultipath/configure.c	Mon Mar 13 15:16:41 2006
@@ -0,0 +1,635 @@
+/*
+ * Copyright (c) 2003, 2004, 2005 Christophe Varoqui
+ * Copyright (c) 2005 Benjamin Marzinski, Redhat
+ * Copyright (c) 2005 Kiyoshi Ueda, NEC
+ * Copyright (c) 2005 Patrick Caulfield, Redhat
+ * Copyright (c) 2005 Edward Goggin, EMC
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/file.h>
+#include <errno.h>
+#include <libdevmapper.h>
+
+#include <checkers.h>
+
+#include "vector.h"
+#include "memory.h"
+#include "devmapper.h"
+#include "defaults.h"
+#include "structs.h"
+#include "structs_vec.h"
+#include "dmparser.h"
+#include "config.h"
+#include "blacklist.h"
+#include "propsel.h"
+#include "discovery.h"
+#include "debug.h"
+#include "switchgroup.h"
+#include "print.h"
+#include "configure.h"
+#include "pgpolicies.h"
+#include "dict.h"
+#include "alias.h"
+
+extern int
+setup_map (struct multipath * mpp)
+{
+	struct pathgroup * pgp;
+	int i;
+	
+	/*
+	 * don't bother if devmap size is unknown
+	 */
+	if (mpp->size <= 0) {
+		condlog(3, "%s: devmap size is unknown", mpp->alias);
+		return 1;
+	}
+
+	/*
+	 * properties selectors
+	 */
+	select_pgfailback(mpp);
+	select_pgpolicy(mpp);
+	select_selector(mpp);
+	select_features(mpp);
+	select_hwhandler(mpp);
+	select_rr_weight(mpp);
+	select_minio(mpp);
+	select_no_path_retry(mpp);
+
+	/*
+	 * assign paths to path groups -- start with no groups and all paths
+	 * in mpp->paths
+	 */
+	if (mpp->pg) {
+		vector_foreach_slot (mpp->pg, pgp, i)
+			free_pathgroup(pgp, KEEP_PATHS);
+
+		vector_free(mpp->pg);
+		mpp->pg = NULL;
+	}
+	if (mpp->pgpolicyfn && mpp->pgpolicyfn(mpp))
+		return 1;
+
+	mpp->nr_active = pathcount(mpp, PATH_UP);
+
+	/*
+	 * ponders each path group and determine highest prio pg
+	 * to switch over (default to first)
+	 */
+	mpp->bestpg = select_path_group(mpp);
+
+	/*
+	 * transform the mp->pg vector of vectors of paths
+	 * into a mp->params strings to feed the device-mapper
+	 */
+	if (assemble_map(mpp)) {
+		condlog(0, "%s: problem assembing map", mpp->alias);
+		return 1;
+	}
+	return 0;
+}
+
+static void
+compute_pgid(struct pathgroup * pgp)
+{
+	struct path * pp;
+	int i;
+
+	vector_foreach_slot (pgp->paths, pp, i)
+		pgp->id ^= (long)pp;
+}
+
+static int
+pgcmp (struct multipath * mpp, struct multipath * cmpp)
+{
+	int i, j;
+	struct pathgroup * pgp;
+	struct pathgroup * cpgp;
+	int r = 0;
+
+	vector_foreach_slot (mpp->pg, pgp, i) {
+		compute_pgid(pgp);
+
+		vector_foreach_slot (cmpp->pg, cpgp, j) {
+			if (pgp->id == cpgp->id) {
+				r = 0;
+				break;
+			}
+			r++;
+		}
+		if (r)
+			return r;
+	}
+	return r;
+}
+
+static void
+select_action (struct multipath * mpp, vector curmp)
+{
+	struct multipath * cmpp;
+
+	cmpp = find_mp_by_alias(curmp, mpp->alias);
+
+	if (!cmpp) {
+		cmpp = find_mp_by_wwid(curmp, mpp->wwid);
+
+		if (cmpp && !conf->dry_run) {
+			condlog(2, "%s: rename %s to %s", mpp->wwid,
+				cmpp->alias, mpp->alias);
+			strncpy(mpp->alias_old, cmpp->alias, WWID_SIZE);
+			mpp->action = ACT_RENAME;
+			return;
+		}
+		else {
+			condlog(3, "%s: set ACT_CREATE (map does not exist)",
+				mpp->alias);
+			mpp->action = ACT_CREATE;
+		}
+		mpp->action = ACT_CREATE;
+		condlog(3, "%s: set ACT_CREATE (map does not exist)",
+			mpp->alias);
+		return;
+	}
+
+	if (!find_mp_by_wwid(curmp, mpp->wwid)) {
+		condlog(2, "%s: remove (wwid changed)", cmpp->alias);
+		dm_flush_map(mpp->alias, DEFAULT_TARGET);
+		strncat(cmpp->wwid, mpp->wwid, WWID_SIZE);
+		drop_multipath(curmp, cmpp->wwid, KEEP_PATHS);
+		mpp->action = ACT_CREATE;
+		condlog(3, "%s: set ACT_CREATE (map wwid change)",
+			mpp->alias);
+		return;
+	}
+		
+	if (pathcount(mpp, PATH_UP) == 0) {
+		mpp->action = ACT_NOTHING;
+		condlog(3, "%s: set ACT_NOTHING (no usable path)",
+			mpp->alias);
+		return;
+	}
+	if (cmpp->size != mpp->size) {
+		mpp->action = ACT_RELOAD;
+		condlog(3, "%s: set ACT_RELOAD (size change)",
+			mpp->alias);
+		return;
+	}
+	if (!mpp->no_path_retry && /* let features be handled by the daemon */
+	    strncmp(cmpp->features, mpp->features, strlen(mpp->features))) {
+		mpp->action =  ACT_RELOAD;
+		condlog(3, "%s: set ACT_RELOAD (features change)",
+			mpp->alias);
+		return;
+	}
+	if (strncmp(cmpp->hwhandler, mpp->hwhandler,
+		    strlen(mpp->hwhandler))) {
+		mpp->action = ACT_RELOAD;
+		condlog(3, "%s: set ACT_RELOAD (hwhandler change)",
+			mpp->alias);
+		return;
+	}
+	if (strncmp(cmpp->selector, mpp->selector,
+		    strlen(mpp->selector))) {
+		mpp->action = ACT_RELOAD;
+		condlog(3, "%s: set ACT_RELOAD (selector change)",
+			mpp->alias);
+		return;
+	}
+	if (cmpp->minio != mpp->minio) {
+		mpp->action = ACT_RELOAD;
+		condlog(3, "%s: set ACT_RELOAD (minio change, %u->%u)",
+			mpp->alias, cmpp->minio, mpp->minio);
+		return;
+	}
+	if (VECTOR_SIZE(cmpp->pg) != VECTOR_SIZE(mpp->pg)) {
+		mpp->action = ACT_RELOAD;
+		condlog(3, "%s: set ACT_RELOAD (path group number change)",
+			mpp->alias);
+		return;
+	}
+	if (pgcmp(mpp, cmpp)) {
+		mpp->action = ACT_RELOAD;
+		condlog(3, "%s: set ACT_RELOAD (path group topology change)",
+			mpp->alias);
+		return;
+	}
+	if (cmpp->nextpg != mpp->bestpg) {
+		mpp->action = ACT_SWITCHPG;
+		condlog(3, "%s: set ACT_SWITCHPG (next path group change)",
+			mpp->alias);
+		return;
+	}
+	mpp->action = ACT_NOTHING;
+	condlog(3, "%s: set ACT_NOTHING (map unchanged)",
+		mpp->alias);
+	return;
+}
+
+extern int
+reinstate_paths (struct multipath * mpp)
+{
+	int i, j;
+	struct pathgroup * pgp;
+	struct path * pp;
+
+	if (!mpp->pg)
+		return 0;
+
+	vector_foreach_slot (mpp->pg, pgp, i) {
+		if (!pgp->paths)
+			continue;
+
+		vector_foreach_slot (pgp->paths, pp, j) {
+			if (pp->state != PATH_UP &&
+			    (pgp->status == PGSTATE_DISABLED ||
+			     pgp->status == PGSTATE_ACTIVE))
+				continue;
+
+			if (pp->dmstate == PSTATE_FAILED) {
+				if (dm_reinstate_path(mpp->alias, pp->dev_t))
+					condlog(0, "%s: error reinstating",
+						pp->dev);
+			}
+		}
+	}
+	return 0;
+}
+
+static int
+lock_multipath (struct multipath * mpp, int lock)
+{
+	struct pathgroup * pgp;
+	struct path * pp;
+	int i, j;
+
+	if (!mpp || !mpp->pg)
+		return 0;
+	
+	vector_foreach_slot (mpp->pg, pgp, i) {
+		if (!pgp->paths)
+			continue;
+		vector_foreach_slot(pgp->paths, pp, j) {
+			if (lock && flock(pp->fd, LOCK_EX | LOCK_NB) &&
+			    errno == EWOULDBLOCK)
+				return 1;
+			else if (!lock)
+				flock(pp->fd, LOCK_UN);
+		}
+	}
+	return 0;
+}
+
+/*
+ * Return value:
+ *  -1: Retry
+ *   0: DM_DEVICE_CREATE or DM_DEVICE_RELOAD failed, or dry_run mode.
+ *   1: DM_DEVICE_CREATE or DM_DEVICE_RELOAD succeeded.
+ *   2: Map is already existing.
+ */
+extern int
+domap (struct multipath * mpp)
+{
+	int r = 0;
+
+	/*
+	 * last chance to quit before touching the devmaps
+	 */
+	if (conf->dry_run) {
+		print_multipath_topology(mpp, conf->verbosity);
+		return 0;
+	}
+
+	switch (mpp->action) {
+	case ACT_REJECT:
+	case ACT_NOTHING:
+		return 2;
+
+	case ACT_SWITCHPG:
+		dm_switchgroup(mpp->alias, mpp->bestpg);
+		/*
+		 * we may have avoided reinstating paths because there where in
+		 * active or disabled PG. Now that the topology has changed,
+		 * retry.
+		 */
+		reinstate_paths(mpp);
+		return 2;
+
+	case ACT_CREATE:
+		if (lock_multipath(mpp, 1)) {
+			condlog(3, "%s: failed to create map (in use)",
+				mpp->alias);
+			return -1;
+		}
+		dm_shut_log();
+
+		if (dm_map_present(mpp->alias))
+			break;
+
+		r = dm_addmap(DM_DEVICE_CREATE, mpp->alias, DEFAULT_TARGET,
+			      mpp->params, mpp->size, mpp->wwid);
+
+		/*
+		 * DM_DEVICE_CREATE is actually DM_DEV_CREATE plus
+		 * DM_TABLE_LOAD. Failing the second part leaves an
+		 * empty map. Clean it up.
+		 */
+		if (!r && dm_map_present(mpp->alias)) {
+			condlog(3, "%s: failed to load map "
+				   "(a path might be in use)",
+				   mpp->alias);
+			dm_flush_map(mpp->alias, DEFAULT_TARGET);
+		}
+
+		lock_multipath(mpp, 0);
+		dm_restore_log();
+		break;
+
+	case ACT_RELOAD:
+		r = (dm_addmap(DM_DEVICE_RELOAD, mpp->alias, DEFAULT_TARGET,
+			      mpp->params, mpp->size, NULL) &&
+		     dm_simplecmd(DM_DEVICE_RESUME, mpp->alias));
+		break;
+
+	case ACT_RENAME:
+		r = dm_rename(mpp->alias_old, mpp->alias);
+		break;
+
+	default:
+		break;
+	}
+
+	if (r) {
+		/*
+		 * DM_DEVICE_CREATE, DM_DEIVCE_RENAME, or DM_DEVICE_RELOAD
+		 * succeeded
+		 */
+#ifndef DAEMON
+		dm_switchgroup(mpp->alias, mpp->bestpg);
+		if (mpp->action != ACT_NOTHING)
+			print_multipath_topology(mpp, conf->verbosity);
+#else
+		mpp->stat_map_loads++;
+		condlog(2, "%s: load table [0 %llu %s %s]", mpp->alias,
+                        mpp->size, DEFAULT_TARGET, mpp->params);
+#endif
+	}
+
+	return r;
+}
+
+static int
+deadmap (struct multipath * mpp)
+{
+	int i, j;
+	struct pathgroup * pgp;
+	struct path * pp;
+
+	if (!mpp->pg)
+		return 1;
+
+	vector_foreach_slot (mpp->pg, pgp, i) {
+		if (!pgp->paths)
+			continue;
+
+		vector_foreach_slot (pgp->paths, pp, j)
+			if (strlen(pp->dev))
+				return 0; /* alive */
+	}
+	
+	return 1; /* dead */
+}
+
+extern int
+coalesce_paths (struct vectors * vecs, vector newmp, char * refwwid)
+{
+	int r = 1;
+	int k, i;
+	char empty_buff[WWID_SIZE];
+	struct multipath * mpp;
+	struct path * pp1;
+	struct path * pp2;
+	vector curmp = vecs->mpvec;
+	vector pathvec = vecs->pathvec;
+
+	memset(empty_buff, 0, WWID_SIZE);
+
+	vector_foreach_slot (pathvec, pp1, k) {
+		/* skip this path for some reason */
+
+		/* 1. if path has no unique id or wwid blacklisted */
+		if (memcmp(empty_buff, pp1->wwid, WWID_SIZE) == 0 ||
+		    blacklist_path(conf, pp1))
+			continue;
+
+		/* 2. if path already coalesced */
+		if (pp1->mpp)
+			continue;
+
+		/* 3. if path has disappeared */
+		if (!pp1->size)
+			continue;
+
+		/* 4. path is out of scope */
+		if (refwwid && strncmp(pp1->wwid, refwwid, WWID_SIZE))
+			continue;
+
+		/*
+		 * at this point, we know we really got a new mp
+		 */
+		if ((mpp = add_map_with_path(vecs, pp1, 0)) == NULL)
+			return 1;
+
+		if (pp1->priority < 0)
+			mpp->action = ACT_REJECT;
+
+		if (!mpp->paths) {
+			condlog(0, "%s: skip coalesce (no paths)", mpp->alias);
+			remove_map(mpp, vecs, NULL, 0);
+			continue;
+		}
+		
+		for (i = k + 1; i < VECTOR_SIZE(pathvec); i++) {
+			pp2 = VECTOR_SLOT(pathvec, i);
+
+			if (strcmp(pp1->wwid, pp2->wwid))
+				continue;
+			
+			if (!pp2->size)
+				continue;
+
+			if (pp2->size != mpp->size) {
+				/*
+				 * ouch, avoid feeding that to the DM
+				 */
+				condlog(0, "%s: size %llu, expected %llu. "
+					"Discard", pp2->dev_t, pp2->size,
+					mpp->size);
+				mpp->action = ACT_REJECT;
+			}
+			if (pp2->priority < 0)
+				mpp->action = ACT_REJECT;
+		}
+		verify_paths(mpp, vecs, NULL);
+		
+		if (setup_map(mpp)) {
+			remove_map(mpp, vecs, NULL, 0);
+			continue;
+		}
+
+		if (mpp->action == ACT_UNDEF)
+			select_action(mpp, curmp);
+
+		r = domap(mpp);
+
+		if (!r) {
+			condlog(3, "%s: domap (%u) failure "
+				   "for create/reload map",
+				mpp->alias, r);
+			remove_map(mpp, vecs, NULL, 0);
+			continue;
+		}
+		else if (r < 0) {
+			condlog(3, "%s: domap (%u) failure "
+				   "for create/reload map",
+				mpp->alias, r);
+			return r;
+		}
+
+		if (mpp->no_path_retry != NO_PATH_RETRY_UNDEF) {
+			if (mpp->no_path_retry == NO_PATH_RETRY_FAIL)
+				dm_queue_if_no_path(mpp->alias, 0);
+			else
+				dm_queue_if_no_path(mpp->alias, 1);
+		}
+
+		if (newmp) {
+			if (mpp->action != ACT_REJECT) {
+				if (!vector_alloc_slot(newmp))
+					return 1;
+				vector_set_slot(newmp, mpp);
+			}
+			else
+				remove_map(mpp, vecs, NULL, 0);
+		}
+	}
+	/*
+	 * Flush maps with only dead paths (ie not in sysfs)
+	 * Keep maps with only failed paths
+	 */
+	if (newmp) {
+		vector_foreach_slot (newmp, mpp, i) {
+			char alias[WWID_SIZE];
+			int j;
+
+			if (!deadmap(mpp))
+				continue;
+
+			strncpy(alias, mpp->alias, WWID_SIZE);
+
+			if ((j = find_slot(newmp, (void *)mpp)) != -1)
+				vector_del_slot(newmp, j);
+
+			remove_map(mpp, vecs, NULL, 0);
+
+			if (dm_flush_map(mpp->alias, DEFAULT_TARGET))
+				condlog(2, "%s: remove failed (dead)",
+					mpp->alias);
+			else
+				condlog(2, "%s: remove (dead)", mpp->alias);
+		}
+	}
+	return 0;
+}
+
+extern char *
+get_refwwid (char * dev, int dev_type, vector pathvec)
+{
+	struct path * pp;
+	char buff[FILE_NAME_SIZE];
+	char * refwwid;
+
+	if (dev_type == DEV_NONE)
+		return NULL;
+
+	if (dev_type == DEV_DEVNODE) {
+		basename(dev, buff);
+		pp = find_path_by_dev(pathvec, buff);
+		
+		if (!pp) {
+			pp = alloc_path();
+
+			if (!pp)
+				return NULL;
+
+			strncpy(pp->dev, buff, FILE_NAME_SIZE);
+
+			if (pathinfo(pp, conf->hwtable, DI_SYSFS | DI_WWID))
+				return NULL;
+
+			if (store_path(pathvec, pp)) {
+				free_path(pp);
+				return NULL;
+			}
+		}
+		refwwid = pp->wwid;
+		goto out;
+	}
+
+	if (dev_type == DEV_DEVT) {
+		pp = find_path_by_devt(pathvec, dev);
+		
+		if (!pp) {
+			if (devt2devname(buff, dev))
+				return NULL;
+
+			pp = alloc_path();
+
+			if (!pp)
+				return NULL;
+
+			strncpy(pp->dev, buff, FILE_NAME_SIZE);
+
+			if (pathinfo(pp, conf->hwtable, DI_SYSFS | DI_WWID))
+				return NULL;
+			
+			if (store_path(pathvec, pp)) {
+				free_path(pp);
+				return NULL;
+			}
+		}
+		refwwid = pp->wwid;
+		goto out;
+	}
+	if (dev_type == DEV_DEVMAP) {
+		/*
+		 * may be a binding
+		 */
+		refwwid = get_user_friendly_wwid(dev,
+						 conf->bindings_file);
+
+		if (refwwid)
+			return refwwid;
+
+		/*
+		 * or may be an alias
+		 */
+		refwwid = get_mpe_wwid(dev);
+
+		/*
+		 * or directly a wwid
+		 */
+		if (!refwwid)
+			refwwid = dev;
+	}
+out:
+	if (refwwid && strlen(refwwid))
+		return STRDUP(refwwid);
+
+	return NULL;
+}
+

Added: multipath-tools/trunk/libmultipath/configure.h
==============================================================================
--- (empty file)
+++ multipath-tools/trunk/libmultipath/configure.h	Mon Mar 13 15:16:41 2006
@@ -0,0 +1,29 @@
+/*
+ * configurator actions
+ */
+#define ACT_NOTHING_STR         "unchanged"
+#define ACT_REJECT_STR          "reject"
+#define ACT_RELOAD_STR          "reload"
+#define ACT_SWITCHPG_STR        "switchpg"
+#define ACT_RENAME_STR          "rename"
+#define ACT_CREATE_STR          "create"
+
+enum actions {
+	ACT_UNDEF,
+	ACT_NOTHING,
+	ACT_REJECT,
+	ACT_RELOAD,
+	ACT_SWITCHPG,
+	ACT_RENAME,
+	ACT_CREATE
+};
+
+#define FLUSH_ONE 1
+#define FLUSH_ALL 2
+
+int setup_map (struct multipath * mpp);
+int domap (struct multipath * mpp);
+int reinstate_paths (struct multipath *mpp);
+int coalesce_paths (struct vectors *vecs, vector curmp, char * refwwid);
+char * get_refwwid (char * dev, int dev_type, vector pathvec);
+

Modified: multipath-tools/trunk/libmultipath/debug.c
==============================================================================
--- multipath-tools/trunk/libmultipath/debug.c	(original)
+++ multipath-tools/trunk/libmultipath/debug.c	Mon Mar 13 15:16:41 2006
@@ -1,11 +1,17 @@
+/*
+ * Copyright (c) 2005 Christophe Varoqui
+ */
 #include <stdio.h>
 #include <stdlib.h>
 #include <stdarg.h>
 
 #if DAEMON
 #include "log_pthread.h"
+#include <sys/types.h>
+#include <time.h>
 #endif
 
+#include "vector.h"
 #include "config.h"
 
 void dlog (int sink, int prio, char * fmt, ...)
@@ -17,13 +23,23 @@
 	thres = (conf) ? conf->verbosity : 0;
 
 	if (prio <= thres) {
+#if DAEMON
 		if (!sink) {
+			time_t t = time(NULL);
+			struct tm *tb = localtime(&t);
+			char buff[16];
+			
+			strftime(buff, 16, "%b %d %H:%M:%S", tb); 
+
+			fprintf(stdout, "%s | ", buff);
 			vfprintf(stdout, fmt, ap);
 			fprintf(stdout, "\n");
 		}
-#if DAEMON
 		else
 			log_safe(prio + 3, fmt, ap);
+#else
+		vfprintf(stdout, fmt, ap);
+		fprintf(stdout, "\n");
 #endif
 	}
 	va_end(ap);

Modified: multipath-tools/trunk/libmultipath/debug.h
==============================================================================
--- multipath-tools/trunk/libmultipath/debug.h	(original)
+++ multipath-tools/trunk/libmultipath/debug.h	Mon Mar 13 15:16:41 2006
@@ -1,4 +1,5 @@
-void dlog (int sink, int prio, char * fmt, ...);
+void dlog (int sink, int prio, char * fmt, ...)
+	__attribute__((format(printf, 3, 4)));
 
 #if DAEMON
 

Modified: multipath-tools/trunk/libmultipath/defaults.c
==============================================================================
--- multipath-tools/trunk/libmultipath/defaults.c	(original)
+++ multipath-tools/trunk/libmultipath/defaults.c	Mon Mar 13 15:16:41 2006
@@ -1,3 +1,6 @@
+/*
+ * Copyright (c) 2005 Christophe Varoqui
+ */
 #include <string.h>
 
 #include "memory.h"

Modified: multipath-tools/trunk/libmultipath/defaults.h
==============================================================================
--- multipath-tools/trunk/libmultipath/defaults.h	(original)
+++ multipath-tools/trunk/libmultipath/defaults.h	Mon Mar 13 15:16:41 2006
@@ -3,12 +3,21 @@
 #define DEFAULT_SELECTOR	"round-robin 0"
 #define DEFAULT_FEATURES	"0"
 #define DEFAULT_HWHANDLER	"0"
-#define DEFAULT_CHECKER		"readsector0"
+#define DEFAULT_MINIO		1000
+#define DEFAULT_GETPRIO		NULL
+#define DEFAULT_PGPOLICY       FAILOVER
+#define DEFAULT_FAILBACK       -FAILBACK_MANUAL
+#define DEFAULT_RR_WEIGHT      RR_WEIGHT_NONE
+#define DEFAULT_NO_PATH_RETRY  NO_PATH_RETRY_UNDEF
+#define DEFAULT_USER_FRIENDLY_NAMES    0
+
+#define DEFAULT_CHECKINT	5
+#define MAX_CHECKINT(a)		(a << 2)
 
 #define DEFAULT_TARGET		"multipath"
 #define DEFAULT_PIDFILE		"/var/run/multipathd.pid"
 #define DEFAULT_SOCKET		"/var/run/multipathd.sock"
 #define DEFAULT_CONFIGFILE	"/etc/multipath.conf"
-#define DEFAULT_BINDINGS_FILE  "/var/lib/multipath/bindings"
+#define DEFAULT_BINDINGS_FILE	"/var/lib/multipath/bindings"
 
 char * set_default (char * str);

Modified: multipath-tools/trunk/libmultipath/devmapper.c
==============================================================================
--- multipath-tools/trunk/libmultipath/devmapper.c	(original)
+++ multipath-tools/trunk/libmultipath/devmapper.c	Mon Mar 13 15:16:41 2006
@@ -1,3 +1,9 @@
+/*
+ * snippets copied from device-mapper dmsetup.c
+ * Copyright (c) 2004, 2005 Christophe Varoqui
+ * Copyright (c) 2005 Kiyoshi Ueda, NEC
+ * Copyright (c) 2005 Patrick Caulfield, Redhat
+ */
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -6,6 +12,8 @@
 #include <linux/kdev_t.h>
 #include <unistd.h>
 
+#include <checkers.h>
+
 #include "vector.h"
 #include "structs.h"
 #include "debug.h"
@@ -381,7 +389,7 @@
 	if (!dm_map_present(mapname))
 		return 0;
 
-	if (!dm_type(mapname, type))
+	if (dm_type(mapname, type) <= 0)
 		return 1;
 
 	if (dm_remove_partmaps(mapname))
@@ -562,7 +570,7 @@
 	do {
 		info = dm_type(names->name, type);
 
-		if (!info)
+		if (info <= 0)
 			goto next;
 
 		mpp = alloc_multipath();
@@ -604,6 +612,35 @@
 	return r;
 }
 
+extern int
+dm_get_name(char *uuid, char *type, char *name)
+{
+	vector vec;
+	struct multipath *mpp;
+	int i;
+
+	vec = vector_alloc();
+
+	if (!vec)
+		return 0;
+
+	if (dm_get_maps(vec, type)) {
+		vector_free(vec);
+		return 0;
+	}
+
+	vector_foreach_slot(vec, mpp, i) {
+		if (!strcmp(uuid, mpp->wwid)) {
+			vector_free(vec);
+			strcpy(name, mpp->alias);
+			return 1;
+		}
+	}
+
+	vector_free(vec);
+	return 0;
+}
+
 int
 dm_geteventnr (char *name)
 {
@@ -640,7 +677,8 @@
 char *
 dm_mapname(int major, int minor)
 {
-	char * response;
+	char * response = NULL;
+	const char *map;
 	struct dm_task *dmt;
 	int r;
 	int loop = MAX_WAIT * LOOPS_PER_SEC;
@@ -674,7 +712,10 @@
 		goto bad;
 	}
 
-	response = STRDUP((char *)dm_task_get_name(dmt));
+	map = dm_task_get_name(dmt);
+	if (map && strlen(map))
+		response = STRDUP((char *)dm_task_get_name(dmt));
+
 	dm_task_destroy(dmt);
 	return response;
 bad:
@@ -718,7 +759,7 @@
 		    /*
 		     * if devmap target is "linear"
 		     */
-		    dm_type(names->name, "linear") &&
+		    (dm_type(names->name, "linear") > 0) &&
 
 		    /*
 		     * and the multipath mapname and the part mapname start
@@ -806,15 +847,91 @@
 	return r;
 }
 
-#if 0
 int
-dm_rename (char * old, char * new)
+dm_rename_partmaps (char * old, char * new)
 {
+	struct dm_task *dmt;
+	struct dm_names *names;
+	unsigned next = 0;
+	char buff[PARAMS_SIZE];
+	unsigned long long size;
+	char dev_t[32];
 	int r = 1;
+
+	if (!(dmt = dm_task_create(DM_DEVICE_LIST)))
+		return 1;
+
+	dm_task_no_open_count(dmt);
+
+	if (!dm_task_run(dmt))
+		goto out;
+
+	if (!(names = dm_task_get_names(dmt)))
+		goto out;
+
+	if (!names->dev) {
+		r = 0; /* this is perfectly valid */
+		goto out;
+	}
+
+	if (dm_dev_t(old, &dev_t[0], 32))
+		goto out;
+
+	do {
+		if (
+		    /*
+		     * if devmap target is "linear"
+		     */
+		    (dm_type(names->name, "linear") > 0) &&
+
+		    /*
+		     * and the multipath mapname and the part mapname start
+		     * the same
+		     */
+		    !strncmp(names->name, old, strlen(old)) &&
+
+		    /*
+		     * and we can fetch the map table from the kernel
+		     */
+		    !dm_get_map(names->name, &size, &buff[0]) &&
+
+		    /*
+		     * and the table maps over the multipath map
+		     */
+		    strstr(buff, dev_t)
+		   ) {
+		    		/*
+				 * then it's a kpartx generated partition.
+				 * Rename it.
+				 */
+				snprintf(buff, PARAMS_SIZE, "%s%s",
+					 new, names->name + strlen(old));
+				dm_rename(names->name, buff);
+				condlog(4, "partition map %s renamed",
+					names->name);
+		   }
+
+		next = names->next;
+		names = (void *) names + next;
+	} while (next);
+
+	r = 0;
+out:
+	dm_task_destroy (dmt);
+	return r;
+}
+
+int
+dm_rename (char * old, char * new)
+{
+	int r = 0;
 	struct dm_task *dmt;
 
+	if (dm_rename_partmaps(old, new))
+		return r;
+
 	if (!(dmt = dm_task_create(DM_DEVICE_RENAME)))
-		return 0;
+		return r;
 
 	if (!dm_task_set_name(dmt, old))
 		goto out;
@@ -827,9 +944,8 @@
 	if (!dm_task_run(dmt))
 		goto out;
 
-	r = 0;
+	r = 1;
 out:
 	dm_task_destroy(dmt);
 	return r;
 }
-#endif

Modified: multipath-tools/trunk/libmultipath/devmapper.h
==============================================================================
--- multipath-tools/trunk/libmultipath/devmapper.h	(original)
+++ multipath-tools/trunk/libmultipath/devmapper.h	Mon Mar 13 15:16:41 2006
@@ -23,7 +23,5 @@
 int dm_remove_partmaps (char * mapname);
 int dm_get_uuid(char *name, char *uuid);
 int dm_get_info (char * mapname, struct dm_info ** dmi);
-
-#if 0
 int dm_rename (char * old, char * new);
-#endif
+int dm_get_name(char * uuid, char * type, char * name);

Modified: multipath-tools/trunk/libmultipath/dict.c
==============================================================================
--- multipath-tools/trunk/libmultipath/dict.c	(original)
+++ multipath-tools/trunk/libmultipath/dict.c	Mon Mar 13 15:16:41 2006
@@ -1,3 +1,11 @@
+/*
+ * Based on Alexandre Cassen template for keepalived
+ * Copyright (c) 2004, 2005, 2006  Christophe Varoqui
+ * Copyright (c) 2005 Benjamin Marzinski, Redhat
+ * Copyright (c) 2005 Kiyoshi Ueda, NEC
+ */
+#include <checkers.h>
+
 #include "vector.h"
 #include "hwtable.h"
 #include "structs.h"
@@ -7,8 +15,7 @@
 #include "memory.h"
 #include "pgpolicies.h"
 #include "blacklist.h"
-
-#include "../libcheckers/checkers.h"
+#include "defaults.h"
 
 /*
  * default block handlers
@@ -20,7 +27,7 @@
 
 	buff = VECTOR_SLOT(strvec, 1);
 	conf->checkint = atoi(buff);
-	conf->max_checkint = conf->checkint << 2;
+	conf->max_checkint = MAX_CHECKINT(conf->checkint);
 
 	return 0;
 }
@@ -57,7 +64,7 @@
 	if (!buff)
 		return 1;
 
-	conf->default_pgpolicy = get_pgpolicy_id(buff);
+	conf->pgpolicy = get_pgpolicy_id(buff);
 	FREE(buff);
 
 	return 0;
@@ -66,9 +73,9 @@
 static int
 def_getuid_callout_handler(vector strvec)
 {
-	conf->default_getuid = set_value(strvec);
+	conf->getuid = set_value(strvec);
 
-	if (!conf->default_getuid)
+	if (!conf->getuid)
 		return 1;
 	
 	return 0;
@@ -77,14 +84,15 @@
 static int
 def_prio_callout_handler(vector strvec)
 {
-	conf->default_getprio = set_value(strvec);
+	conf->getprio = set_value(strvec);
 
-	if (!conf->default_getprio)
+	if (!conf->getprio)
 		return 1;
 	
-	if (!strncmp(conf->default_getprio, "none", 4)) {
-		FREE(conf->default_getprio);
-		conf->default_getprio = NULL;
+	if (strlen(conf->getprio) == 4 &&
+	    !strcmp(conf->getprio, "none")) {
+		FREE(conf->getprio);
+		conf->getprio = NULL;
 	}
 		
 	return 0;
@@ -111,7 +119,7 @@
 	if (!buff)
 		return 1;
 	
-	conf->default_checker_index = get_checker_id(buff);
+	conf->checker = checker_lookup(buff);
 	FREE(buff);
 
 	return 0;
@@ -159,9 +167,9 @@
 
 	buff = set_value(strvec);
 
-	if (!strncmp(buff, "manual", 6))
+	if (strlen(buff) == 6 && !strcmp(buff, "manual"))
 		conf->pgfailback = -FAILBACK_MANUAL;
-	else if (!strncmp(buff, "immediate", 9))
+	else if (strlen(buff) == 9 && !strcmp(buff, "immediate"))
 		conf->pgfailback = -FAILBACK_IMMEDIATE;
 	else
 		conf->pgfailback = atoi(buff);
@@ -180,9 +188,10 @@
 	if (!buff)
 		return 1;
 
-	if (!strncmp(buff, "fail", 4) || !strncmp(buff, "0", 1))
+	if ((strlen(buff) == 4 && !strcmp(buff, "fail")) ||
+	    (strlen(buff) == 1 && !strcmp(buff, "0")))
 		conf->no_path_retry = NO_PATH_RETRY_FAIL;
-	else if (!strncmp(buff, "queue", 5))
+	else if (strlen(buff) == 5 && !strcmp(buff, "queue"))
 		conf->no_path_retry = NO_PATH_RETRY_QUEUE;
 	else if ((conf->no_path_retry = atoi(buff)) < 1)
 		conf->no_path_retry = NO_PATH_RETRY_UNDEF;
@@ -201,9 +210,11 @@
 	if (!buff)
 		return 1;
 
-	if (!strncmp(buff, "no", 2) || !strncmp(buff, "0", 1))
+	if ((strlen(buff) == 2 && !strcmp(buff, "no")) ||
+	    (strlen(buff) == 1 && !strcmp(buff, "0")))
 		conf->user_friendly_names = 0;
-	else if (!strncmp(buff, "yes", 2) || !strncmp(buff, "1", 1))
+	else if ((strlen(buff) == 3 && !strcmp(buff, "yes")) ||
+		 (strlen(buff) == 1 && !strcmp(buff, "1")))
 		conf->user_friendly_names = 1;
 
 	FREE(buff);
@@ -216,29 +227,72 @@
 static int
 blacklist_handler(vector strvec)
 {
-	conf->blist = vector_alloc();
+	conf->blist_devnode = vector_alloc();
+	conf->blist_wwid = vector_alloc();
+	conf->blist_device = vector_alloc();
 
-	if (!conf->blist)
+	if (!conf->blist_devnode || !conf->blist_wwid || !conf->blist_device)
 		return 1;
 
 	return 0;
 }
 
 static int
-ble_handler(vector strvec)
+ble_devnode_handler(vector strvec)
 {
 	char * buff;
-	int ret;
 
 	buff = set_value(strvec);
 
 	if (!buff)
 		return 1;
 
-	ret = store_regex(conf->blist, buff);
-	FREE(buff);
+	return store_ble(conf->blist_devnode, buff);
+}
+
+static int
+ble_wwid_handler(vector strvec)
+{
+	char * buff;
+
+	buff = set_value(strvec);
+
+	if (!buff)
+		return 1;
 
-	return ret;
+	return store_ble(conf->blist_wwid, buff);
+}
+
+static int
+ble_device_handler(vector strvec)
+{
+	return alloc_ble_device(conf->blist_device);
+}
+
+static int
+ble_vendor_handler(vector strvec)
+{
+	char * buff;
+
+	buff = set_value(strvec);
+
+	if (!buff)
+		return 1;
+
+	return set_ble_device(conf->blist_device, buff, NULL);
+}
+
+static int
+ble_product_handler(vector strvec)
+{
+	char * buff;
+
+	buff = set_value(strvec);
+
+	if (!buff)
+		return 1;
+
+	return set_ble_device(conf->blist_device, NULL, buff);
 }
 
 /*
@@ -307,6 +361,21 @@
 }
 
 static int
+bl_product_handler(vector strvec)
+{
+	struct hwentry * hwe = VECTOR_LAST_SLOT(conf->hwtable);
+
+	if (!hwe)
+		return 1;
+
+	hwe->bl_product = set_value(strvec);
+	if (!hwe->bl_product)
+		return 1;
+
+	return 0;
+}
+
+static int
 hw_pgpolicy_handler(vector strvec)
 {
 	char * buff;
@@ -366,7 +435,7 @@
 	if (!buff)
 		return 1;
 	
-	hwe->checker_index = get_checker_id(buff);
+	hwe->checker = checker_lookup(buff);
 	FREE(buff);
 
 	return 0;
@@ -417,7 +486,7 @@
 	if (!hwe->getprio)
 		return 1;
 
-	if (!strncmp(hwe->getprio, "none", 4)) {
+	if (strlen(hwe->getprio) == 4 && !strcmp(hwe->getprio, "none")) {
 		FREE(hwe->getprio);
 		hwe->getprio = NULL;
 	}
@@ -436,9 +505,9 @@
 
 	buff = set_value(strvec);
 
-	if (!strncmp(buff, "manual", 6))
+	if (strlen(buff) == 6 && !strcmp(buff, "manual"))
 		hwe->pgfailback = -FAILBACK_MANUAL;
-	else if (!strncmp(buff, "immediate", 9))
+	else if (strlen(buff) == 9 && !strcmp(buff, "immediate"))
 		hwe->pgfailback = -FAILBACK_IMMEDIATE;
 	else
 		hwe->pgfailback = atoi(buff);
@@ -484,9 +553,10 @@
 	if (!buff)
 		return 1;
 
-	if (!strncmp(buff, "fail", 4) || !strncmp(buff, "0", 1))
+	if ((strlen(buff) == 4 && !strcmp(buff, "fail")) ||
+	    (strlen(buff) == 1 && !strcmp(buff, "0")))
 		hwe->no_path_retry = NO_PATH_RETRY_FAIL;
-	else if (!strncmp(buff, "queue", 5))
+	else if (strlen(buff) == 5 && !strcmp(buff, "queue"))
 		hwe->no_path_retry = NO_PATH_RETRY_QUEUE;
 	else if ((hwe->no_path_retry = atoi(buff)) < 1)
 		hwe->no_path_retry = NO_PATH_RETRY_UNDEF;
@@ -495,6 +565,26 @@
 	return 0;
 }
 
+static int
+hw_minio_handler(vector strvec)
+{
+	struct hwentry *hwe = VECTOR_LAST_SLOT(conf->hwtable);
+	char * buff;
+
+	if (!hwe)
+		return 1;
+
+	buff = set_value(strvec);
+
+	if (!buff)
+		return 1;
+
+	hwe->minio = atoi(buff);
+	FREE(buff);
+
+	return 0;
+}
+
 /*
  * multipaths block handlers
  */
@@ -607,9 +697,9 @@
 
 	buff = set_value(strvec);
 
-	if (!strncmp(buff, "manual", 6))
+	if (strlen(buff) == 6 && !strcmp(buff, "manual"))
 		mpe->pgfailback = -FAILBACK_MANUAL;
-	else if (!strncmp(buff, "immediate", 9))
+	else if (strlen(buff) == 9 && !strcmp(buff, "immediate"))
 		mpe->pgfailback = -FAILBACK_IMMEDIATE;
 	else
 		mpe->pgfailback = atoi(buff);
@@ -655,9 +745,10 @@
 	if (!buff)
 		return 1;
 
-	if (!strncmp(buff, "fail", 4) || !strncmp(buff, "0", 1))
+	if ((strlen(buff) == 4 && !strcmp(buff, "fail")) ||
+	    (strlen(buff) == 1 && !strcmp(buff, "0")))
 		mpe->no_path_retry = NO_PATH_RETRY_FAIL;
-	else if (!strncmp(buff, "queue", 5))
+	else if (strlen(buff) == 5 && !strcmp(buff, "queue"))
 		mpe->no_path_retry = NO_PATH_RETRY_QUEUE;
 	else if ((mpe->no_path_retry = atoi(buff)) < 1)
 		mpe->no_path_retry = NO_PATH_RETRY_UNDEF;
@@ -666,68 +757,626 @@
 	return 0;
 }
 
-vector
-init_keywords(void)
+static int
+mp_minio_handler(vector strvec)
+{
+	struct mpentry *mpe = VECTOR_LAST_SLOT(conf->mptable);
+	char * buff;
+
+	if (!mpe)
+		return 1;
+
+	buff = set_value(strvec);
+
+	if (!buff)
+		return 1;
+
+	mpe->minio = atoi(buff);
+	FREE(buff);
+
+	return 0;
+}
+
+/*
+ * config file keywords printing
+ */
+static int
+snprint_mp_wwid (char * buff, int len, void * data)
+{
+	struct mpentry * mpe = (struct mpentry *)data;
+
+	return snprintf(buff, len, "%s", mpe->wwid);
+}
+
+static int
+snprint_mp_alias (char * buff, int len, void * data)
+{
+	struct mpentry * mpe = (struct mpentry *)data;
+
+	if (!mpe->alias)
+		return 0;
+
+	if (conf->user_friendly_names &&
+	    (strlen(mpe->alias) == strlen("mpath")) &&
+	    !strcmp(mpe->alias, "mpath"))
+		return 0;
+
+	return snprintf(buff, len, "%s", mpe->alias);
+}
+
+static int
+snprint_mp_path_grouping_policy (char * buff, int len, void * data)
+{
+	struct mpentry * mpe = (struct mpentry *)data;
+	char str[POLICY_NAME_SIZE];
+
+	if (!mpe->pgpolicy)
+		return 0;
+	get_pgpolicy_name(str, POLICY_NAME_SIZE, mpe->pgpolicy);
+	
+	return snprintf(buff, len, "%s", str);
+}
+
+static int
+snprint_mp_selector (char * buff, int len, void * data)
+{
+	struct mpentry * mpe = (struct mpentry *)data;
+
+	if (!mpe->selector)
+		return 0;
+
+	return snprintf(buff, len, "%s", mpe->selector);
+}
+
+static int
+snprint_mp_failback (char * buff, int len, void * data)
+{
+	struct mpentry * mpe = (struct mpentry *)data;
+
+	if (!mpe->pgfailback)
+		return 0;
+
+	switch(mpe->pgfailback) {
+	case  FAILBACK_UNDEF:
+		break;
+	case -FAILBACK_MANUAL:
+		return snprintf(buff, len, "manual");
+	case -FAILBACK_IMMEDIATE:
+		return snprintf(buff, len, "immediate");
+	default:
+		return snprintf(buff, len, "%i", mpe->pgfailback);
+	}
+	return 0;
+}
+
+static int
+snprint_mp_rr_weight (char * buff, int len, void * data)
+{
+	struct mpentry * mpe = (struct mpentry *)data;
+
+	if (!mpe->rr_weight)
+		return 0;
+	if (mpe->rr_weight == RR_WEIGHT_PRIO)
+		return snprintf(buff, len, "priorities");
+
+	return 0;
+}
+
+static int
+snprint_mp_no_path_retry (char * buff, int len, void * data)
+{
+	struct mpentry * mpe = (struct mpentry *)data;
+
+	if (!mpe->no_path_retry)
+		return 0;
+
+	switch(mpe->no_path_retry) {
+	case NO_PATH_RETRY_UNDEF:
+		break;
+	case NO_PATH_RETRY_FAIL:
+		return snprintf(buff, len, "fail");
+	case NO_PATH_RETRY_QUEUE:
+		return snprintf(buff, len, "queue");
+	default:
+		return snprintf(buff, len, "%i",
+				mpe->no_path_retry);
+	}
+	return 0;
+}
+
+static int
+snprint_mp_rr_min_io (char * buff, int len, void * data)
+{
+	struct mpentry * mpe = (struct mpentry *)data;
+
+	if (!mpe->minio)
+		return 0;
+
+	return snprintf(buff, len, "%u", mpe->minio);
+}
+
+static int
+snprint_hw_vendor (char * buff, int len, void * data)
+{
+	struct hwentry * hwe = (struct hwentry *)data;
+
+	if (!hwe->vendor)
+		return 0;
+
+	return snprintf(buff, len, "%s", hwe->vendor);
+}
+
+static int
+snprint_hw_product (char * buff, int len, void * data)
+{
+	struct hwentry * hwe = (struct hwentry *)data;
+
+	if (!hwe->product)
+		return 0;
+
+	return snprintf(buff, len, "%s", hwe->product);
+}
+
+static int
+snprint_hw_bl_product (char * buff, int len, void * data)
+{
+	struct hwentry * hwe = (struct hwentry *)data;
+
+	if (!hwe->bl_product)
+		return 0;
+
+	return snprintf(buff, len, "%s", hwe->bl_product);
+}
+
+static int
+snprint_hw_getuid_callout (char * buff, int len, void * data)
+{
+	struct hwentry * hwe = (struct hwentry *)data;
+
+	if (!hwe->getuid)
+		return 0;
+	if (strlen(hwe->getuid) == strlen(conf->getuid) &&
+	    !strcmp(hwe->getuid, conf->getuid))
+		return 0;
+
+	return snprintf(buff, len, "%s", hwe->getuid);
+}
+
+static int
+snprint_hw_prio_callout (char * buff, int len, void * data)
+{
+	struct hwentry * hwe = (struct hwentry *)data;
+
+	if (!conf->getprio && !hwe->getprio)
+		return 0;
+	if (!conf->getprio && hwe->getprio)
+		return snprintf(buff, len, "%s", hwe->getprio);
+	if (conf->getprio && !hwe->getprio)
+		return snprintf(buff, len, "none");
+
+	/* conf->getprio && hwe->getprio */
+	if (strlen(hwe->getprio) == strlen(conf->getprio) &&
+	    !strcmp(hwe->getprio, conf->getprio))
+		return 0;
+
+	return snprintf(buff, len, "%s", hwe->getprio);
+}
+
+static int
+snprint_hw_features (char * buff, int len, void * data)
 {
-	keywords = vector_alloc();
+	struct hwentry * hwe = (struct hwentry *)data;
+
+	if (!hwe->features)
+		return 0;
+	if (strlen(hwe->features) == strlen(conf->features) &&
+	    !strcmp(hwe->features, conf->features))
+		return 0;
+
+	return snprintf(buff, len, "%s", hwe->features);
+}
+
+static int
+snprint_hw_hardware_handler (char * buff, int len, void * data)
+{
+	struct hwentry * hwe = (struct hwentry *)data;
+
+	if (!hwe->hwhandler)
+		return 0;
+	if (strlen(hwe->hwhandler) == strlen(conf->hwhandler) &&
+	    !strcmp(hwe->hwhandler, conf->hwhandler))
+		return 0;
+
+	return snprintf(buff, len, "%s", hwe->hwhandler);
+}
+
+static int
+snprint_hw_selector (char * buff, int len, void * data)
+{
+	struct hwentry * hwe = (struct hwentry *)data;
+
+	if (!hwe->selector)
+		return 0;
+	if (strlen(hwe->selector) == strlen(conf->selector) &&
+	    !strcmp(hwe->selector, conf->selector))
+		return 0;
+
+	return snprintf(buff, len, "%s", hwe->selector);
+}
+
+static int
+snprint_hw_path_grouping_policy (char * buff, int len, void * data)
+{
+	struct hwentry * hwe = (struct hwentry *)data;
+
+	char str[POLICY_NAME_SIZE];
+
+	if (!hwe->pgpolicy)
+		return 0;
+	if (hwe->pgpolicy == conf->pgpolicy)
+		return 0;
+
+	get_pgpolicy_name(str, POLICY_NAME_SIZE, hwe->pgpolicy);
+	
+	return snprintf(buff, len, "%s", str);
+}
+
+static int
+snprint_hw_failback (char * buff, int len, void * data)
+{
+	struct hwentry * hwe = (struct hwentry *)data;
+
+	if (!hwe->pgfailback)
+		return 0;
+	if (hwe->pgfailback == conf->pgfailback)
+		return 0;
 
+	switch(hwe->pgfailback) {
+	case  FAILBACK_UNDEF:
+		break;
+	case -FAILBACK_MANUAL:
+		return snprintf(buff, len, "manual");
+	case -FAILBACK_IMMEDIATE:
+		return snprintf(buff, len, "immediate");
+	default:
+		return snprintf(buff, len, "%i", hwe->pgfailback);
+	}
+	return 0;
+}
+
+static int
+snprint_hw_rr_weight (char * buff, int len, void * data)
+{
+	struct hwentry * hwe = (struct hwentry *)data;
+
+	if (!hwe->rr_weight)
+		return 0;
+	if (hwe->rr_weight == conf->rr_weight)
+		return 0;
+	if (hwe->rr_weight == RR_WEIGHT_PRIO)
+		return snprintf(buff, len, "priorities");
+
+	return 0;
+}
+
+static int
+snprint_hw_no_path_retry (char * buff, int len, void * data)
+{
+	struct hwentry * hwe = (struct hwentry *)data;
+
+	if (!hwe->no_path_retry)
+		return 0;
+	if (hwe->no_path_retry == conf->no_path_retry)
+		return 0;
+
+	switch(hwe->no_path_retry) {
+	case NO_PATH_RETRY_UNDEF:
+		break;
+	case NO_PATH_RETRY_FAIL:
+		return snprintf(buff, len, "fail");
+	case NO_PATH_RETRY_QUEUE:
+		return snprintf(buff, len, "queue");
+	default:
+		return snprintf(buff, len, "%i",
+				hwe->no_path_retry);
+	}
+	return 0;
+}
+
+static int
+snprint_hw_rr_min_io (char * buff, int len, void * data)
+{
+	struct hwentry * hwe = (struct hwentry *)data;
+
+	if (!hwe->minio)
+		return 0;
+	if (hwe->minio == conf->minio)
+		return 0;
+
+	return snprintf(buff, len, "%u", hwe->minio);
+}
+
+static int
+snprint_hw_path_checker (char * buff, int len, void * data)
+{
+	struct hwentry * hwe = (struct hwentry *)data;
+
+	if (!hwe->checker)
+		return 0;
+	if (!checker_selected(hwe->checker))
+		return 0;
+	if (hwe->checker == conf->checker)
+		return 0;
+	
+	return snprintf(buff, len, "%s", checker_name(hwe->checker));
+}
+
+static int
+snprint_def_polling_interval (char * buff, int len, void * data)
+{
+	if (conf->checkint == DEFAULT_CHECKINT)
+		return 0;
+	return snprintf(buff, len, "%i", conf->checkint);
+}
+
+static int
+snprint_def_udev_dir (char * buff, int len, void * data)
+{
+	if (!conf->udev_dir)
+		return 0;
+	if (strlen(DEFAULT_UDEVDIR) == strlen(conf->udev_dir) &&
+	    !strcmp(conf->udev_dir, DEFAULT_UDEVDIR))
+		return 0;
+
+	return snprintf(buff, len, "%s", conf->udev_dir);
+}
+
+static int
+snprint_def_selector (char * buff, int len, void * data)
+{
+	if (!conf->selector)
+		return 0;
+	if (strlen(conf->selector) == strlen(DEFAULT_SELECTOR) &&
+	    !strcmp(conf->selector, DEFAULT_SELECTOR))
+		return 0;
+
+	return snprintf(buff, len, "%s", conf->selector);
+}
+
+static int
+snprint_def_path_grouping_policy (char * buff, int len, void * data)
+{
+	char str[POLICY_NAME_SIZE];
+
+	if (!conf->pgpolicy)
+		return 0;
+	if (conf->pgpolicy == DEFAULT_PGPOLICY)
+		return 0;
+
+	get_pgpolicy_name(str, POLICY_NAME_SIZE, conf->pgpolicy);
+	
+	return snprintf(buff, len, "%s", str);
+}
+
+static int
+snprint_def_getuid_callout (char * buff, int len, void * data)
+{
+	if (!conf->getuid)
+		return 0;
+	if (strlen(conf->getuid) == strlen(DEFAULT_GETUID) &&
+	    !strcmp(conf->getuid, DEFAULT_GETUID))
+		return 0;
+
+	return snprintf(buff, len, "%s", conf->getuid);
+}
+
+static int
+snprint_def_getprio_callout (char * buff, int len, void * data)
+{
+	if (!conf->getprio)
+		return 0;
+
+	return snprintf(buff, len, "%s", conf->getprio);
+}
+
+static int
+snprint_def_features (char * buff, int len, void * data)
+{
+	if (!conf->features)
+		return 0;
+	if (strlen(conf->features) == strlen(DEFAULT_FEATURES) &&
+	    !strcmp(conf->features, DEFAULT_FEATURES))
+		return 0;
+
+	return snprintf(buff, len, "%s", conf->features);
+}
+
+static int
+snprint_def_path_checker (char * buff, int len, void * data)
+{
+	if (!conf->checker)
+		return 0;
+	if (conf->checker == checker_default())
+		return 0;
+	
+	return snprintf(buff, len, "%s", checker_name(conf->checker));
+}
+
+static int
+snprint_def_failback (char * buff, int len, void * data)
+{
+	if (!conf->pgfailback)
+		return 0;
+	if (conf->pgfailback == DEFAULT_FAILBACK)
+		return 0;
+
+	switch(conf->pgfailback) {
+	case  FAILBACK_UNDEF:
+		break;
+	case -FAILBACK_MANUAL:
+		return snprintf(buff, len, "manual");
+	case -FAILBACK_IMMEDIATE:
+		return snprintf(buff, len, "immediate");
+	default:
+		return snprintf(buff, len, "%i", conf->pgfailback);
+	}
+	return 0;
+}
+
+static int
+snprint_def_rr_min_io (char * buff, int len, void * data)
+{
+	if (!conf->minio)
+		return 0;
+	if (conf->minio == DEFAULT_MINIO)
+		return 0;
+
+	return snprintf(buff, len, "%u", conf->minio);
+}
+
+static int
+snprint_def_rr_weight (char * buff, int len, void * data)
+{
+	if (!conf->rr_weight)
+		return 0;
+	if (conf->rr_weight == DEFAULT_RR_WEIGHT)
+		return 0;
+	if (conf->rr_weight == RR_WEIGHT_PRIO)
+		return snprintf(buff, len, "priorities");
+
+	return 0;
+}
+
+static int
+snprint_def_no_path_retry (char * buff, int len, void * data)
+{
+	if (conf->no_path_retry == DEFAULT_NO_PATH_RETRY)
+		return 0;
+
+	switch(conf->no_path_retry) {
+	case NO_PATH_RETRY_UNDEF:
+		break;
+	case NO_PATH_RETRY_FAIL:
+		return snprintf(buff, len, "fail");
+	case NO_PATH_RETRY_QUEUE:
+		return snprintf(buff, len, "queue");
+	default:
+		return snprintf(buff, len, "%i",
+				conf->no_path_retry);
+	}
+	return 0;
+}
+
+static int
+snprint_def_user_friendly_names (char * buff, int len, void * data)
+{
+	if (conf->user_friendly_names == DEFAULT_USER_FRIENDLY_NAMES)
+		return 0;
+	if (!conf->user_friendly_names)
+		return snprintf(buff, len, "no");
+
+	return snprintf(buff, len, "yes");
+}
+
+static int
+snprint_ble_simple (char * buff, int len, void * data)
+{
+	struct blentry * ble = (struct blentry *)data;
+
+	return snprintf(buff, len, "%s", ble->str);
+}
+
+static int
+snprint_bled_vendor (char * buff, int len, void * data)
+{
+	struct blentry_device * bled = (struct blentry_device *)data;
+
+	return snprintf(buff, len, "%s", bled->vendor);
+}
+	
+static int
+snprint_bled_product (char * buff, int len, void * data)
+{
+	struct blentry_device * bled = (struct blentry_device *)data;
+
+	return snprintf(buff, len, "%s", bled->product);
+}
+	
+#define __deprecated
+
+void
+init_keywords(void)
+{
 	install_keyword_root("defaults", NULL);
-	install_keyword("polling_interval", &polling_interval_handler);
-	install_keyword("udev_dir", &udev_dir_handler);
-	install_keyword("selector", &def_selector_handler);
-	install_keyword("path_grouping_policy", &def_pgpolicy_handler);
-	install_keyword("getuid_callout", &def_getuid_callout_handler);
-	install_keyword("prio_callout", &def_prio_callout_handler);
-	install_keyword("features", &def_features_handler);
-	install_keyword("path_checker", &def_path_checker_handler);
-	install_keyword("failback", &default_failback_handler);
-	install_keyword("rr_min_io", &def_minio_handler);
-	install_keyword("rr_weight", &def_weight_handler);
-	install_keyword("no_path_retry", &def_no_path_retry_handler);
-	install_keyword("user_friendly_names", &names_handler);
-
-	/*
-	 * deprecated synonyms
-	 */
-	install_keyword("default_selector", &def_selector_handler);
-	install_keyword("default_path_grouping_policy", &def_pgpolicy_handler);
-	install_keyword("default_getuid_callout", &def_getuid_callout_handler);
-	install_keyword("default_prio_callout", &def_prio_callout_handler);
-	install_keyword("default_features", &def_features_handler);
-	install_keyword("default_path_checker", &def_path_checker_handler);
-
-	install_keyword_root("devnode_blacklist", &blacklist_handler);
-	install_keyword("devnode", &ble_handler);
-	install_keyword("wwid", &ble_handler);
+	install_keyword("polling_interval", &polling_interval_handler, &snprint_def_polling_interval);
+	install_keyword("udev_dir", &udev_dir_handler, &snprint_def_udev_dir);
+	install_keyword("selector", &def_selector_handler, &snprint_def_selector);
+	install_keyword("path_grouping_policy", &def_pgpolicy_handler, &snprint_def_path_grouping_policy);
+	install_keyword("getuid_callout", &def_getuid_callout_handler, &snprint_def_getuid_callout);
+	install_keyword("prio_callout", &def_prio_callout_handler, &snprint_def_getprio_callout);
+	install_keyword("features", &def_features_handler, &snprint_def_features);
+	install_keyword("path_checker", &def_path_checker_handler, &snprint_def_path_checker);
+	install_keyword("failback", &default_failback_handler, &snprint_def_failback);
+	install_keyword("rr_min_io", &def_minio_handler, &snprint_def_rr_min_io);
+	install_keyword("rr_weight", &def_weight_handler, &snprint_def_rr_weight);
+	install_keyword("no_path_retry", &def_no_path_retry_handler, &snprint_def_no_path_retry);
+	install_keyword("user_friendly_names", &names_handler, &snprint_def_user_friendly_names);
+	__deprecated install_keyword("default_selector", &def_selector_handler, NULL);
+	__deprecated install_keyword("default_path_grouping_policy", &def_pgpolicy_handler, NULL);
+	__deprecated install_keyword("default_getuid_callout", &def_getuid_callout_handler, NULL);
+	__deprecated install_keyword("default_prio_callout", &def_prio_callout_handler, NULL);
+	__deprecated install_keyword("default_features", &def_features_handler, NULL);
+	__deprecated install_keyword("default_path_checker", &def_path_checker_handler, NULL);
+
+	install_keyword_root("blacklist", &blacklist_handler);
+	install_keyword("devnode", &ble_devnode_handler, &snprint_ble_simple);
+	install_keyword("wwid", &ble_wwid_handler, &snprint_ble_simple);
+	install_keyword("device", &ble_device_handler, NULL);
+	install_sublevel();
+	install_keyword("vendor", &ble_vendor_handler, &snprint_bled_vendor);
+	install_keyword("product", &ble_product_handler, &snprint_bled_product);
+	install_sublevel_end();
+
+#if 0
+	__deprecated install_keyword_root("devnode_blacklist", &blacklist_handler);
+	__deprecated install_keyword("devnode", &ble_devnode_handler, &snprint_ble_simple);
+	__deprecated install_keyword("wwid", &ble_wwid_handler, &snprint_ble_simple);
+	__deprecated install_keyword("device", &ble_device_handler, NULL);
+	__deprecated install_sublevel();
+	__deprecated install_keyword("vendor", &ble_vendor_handler, &snprint_bled_vendor);
+	__deprecated install_keyword("product", &ble_product_handler, &snprint_bled_product);
+	__deprecated install_sublevel_end();
+#endif
 
 	install_keyword_root("devices", &devices_handler);
-	install_keyword("device", &device_handler);
+	install_keyword("device", &device_handler, NULL);
 	install_sublevel();
-	install_keyword("vendor", &vendor_handler);
-	install_keyword("product", &product_handler);
-	install_keyword("path_grouping_policy", &hw_pgpolicy_handler);
-	install_keyword("getuid_callout", &hw_getuid_callout_handler);
-	install_keyword("path_selector", &hw_selector_handler);
-	install_keyword("path_checker", &hw_path_checker_handler);
-	install_keyword("features", &hw_features_handler);
-	install_keyword("hardware_handler", &hw_handler_handler);
-	install_keyword("prio_callout", &prio_callout_handler);
-	install_keyword("failback", &hw_failback_handler);
-	install_keyword("rr_weight", &hw_weight_handler);
-	install_keyword("no_path_retry", &hw_no_path_retry_handler);
+	install_keyword("vendor", &vendor_handler, &snprint_hw_vendor);
+	install_keyword("product", &product_handler, &snprint_hw_product);
+	install_keyword("product_blacklist", &bl_product_handler, &snprint_hw_bl_product);
+	install_keyword("path_grouping_policy", &hw_pgpolicy_handler, &snprint_hw_path_grouping_policy);
+	install_keyword("getuid_callout", &hw_getuid_callout_handler, &snprint_hw_getuid_callout);
+	install_keyword("path_selector", &hw_selector_handler, &snprint_hw_selector);
+	install_keyword("path_checker", &hw_path_checker_handler, &snprint_hw_path_checker);
+	install_keyword("features", &hw_features_handler, &snprint_hw_features);
+	install_keyword("hardware_handler", &hw_handler_handler, &snprint_hw_hardware_handler);
+	install_keyword("prio_callout", &prio_callout_handler, &snprint_hw_prio_callout);
+	install_keyword("failback", &hw_failback_handler, &snprint_hw_failback);
+	install_keyword("rr_weight", &hw_weight_handler, &snprint_hw_rr_weight);
+	install_keyword("no_path_retry", &hw_no_path_retry_handler, &snprint_hw_no_path_retry);
+	install_keyword("rr_min_io", &hw_minio_handler, &snprint_hw_rr_min_io);
 	install_sublevel_end();
 
 	install_keyword_root("multipaths", &multipaths_handler);
-	install_keyword("multipath", &multipath_handler);
+	install_keyword("multipath", &multipath_handler, NULL);
 	install_sublevel();
-	install_keyword("wwid", &wwid_handler);
-	install_keyword("alias", &alias_handler);
-	install_keyword("path_grouping_policy", &mp_pgpolicy_handler);
-	install_keyword("path_selector", &mp_selector_handler);
-	install_keyword("failback", &mp_failback_handler);
-	install_keyword("rr_weight", &mp_weight_handler);
-	install_keyword("no_path_retry", &mp_no_path_retry_handler);
+	install_keyword("wwid", &wwid_handler, &snprint_mp_wwid);
+	install_keyword("alias", &alias_handler, &snprint_mp_alias);
+	install_keyword("path_grouping_policy", &mp_pgpolicy_handler, &snprint_mp_path_grouping_policy);
+	install_keyword("path_selector", &mp_selector_handler, &snprint_mp_selector);
+	install_keyword("failback", &mp_failback_handler, &snprint_mp_failback);
+	install_keyword("rr_weight", &mp_weight_handler, &snprint_mp_rr_weight);
+	install_keyword("no_path_retry", &mp_no_path_retry_handler, &snprint_mp_no_path_retry);
+	install_keyword("rr_min_io", &mp_minio_handler, &snprint_mp_rr_min_io);
 	install_sublevel_end();
-
-	return keywords;
 }

Modified: multipath-tools/trunk/libmultipath/dict.h
==============================================================================
--- multipath-tools/trunk/libmultipath/dict.h	(original)
+++ multipath-tools/trunk/libmultipath/dict.h	Mon Mar 13 15:16:41 2006
@@ -5,6 +5,6 @@
 #include "vector.h"
 #endif
 
-vector init_keywords(void);
+void init_keywords(void);
 
 #endif /* _DICT_H */

Modified: multipath-tools/trunk/libmultipath/discovery.c
==============================================================================
--- multipath-tools/trunk/libmultipath/discovery.c	(original)
+++ multipath-tools/trunk/libmultipath/discovery.c	Mon Mar 13 15:16:41 2006
@@ -1,30 +1,31 @@
+/*
+ * Copyright (c) 2004, 2005, 2006 Christophe Varoqui
+ * Copyright (c) 2005 Stefan Bader, IBM
+ * Copyright (c) 2005 Mike Anderson
+ */
 #include <stdio.h>
 #include <unistd.h>
 #include <fcntl.h>
 #include <sys/ioctl.h>
 #include <sys/stat.h>
 #include <errno.h>
-
 #include <sysfs/dlist.h>
 #include <sysfs/libsysfs.h>
 
+#include <checkers.h>
+
 #include "vector.h"
 #include "memory.h"
-#include "blacklist.h"
 #include "util.h"
 #include "structs.h"
-#include "callout.h"
 #include "config.h"
+#include "blacklist.h"
+#include "callout.h"
 #include "debug.h"
 #include "propsel.h"
 #include "sg_include.h"
 #include "discovery.h"
 
-#include "../libcheckers/path_state.h"
-
-#define readattr(a,b) \
-	sysfs_read_attribute_value(a, b, sizeof(b))
-
 struct path *
 store_pathinfo (vector pathvec, vector hwtable, char * devname, int flag)
 {
@@ -51,67 +52,58 @@
 	return NULL;
 }
 
-int
-path_discovery (vector pathvec, struct config * conf, int flag)
+static int
+path_discover (vector pathvec, struct config * conf, char * devname, int flag)
 {
-	struct sysfs_directory * sdir;
-	struct sysfs_directory * devp;
 	char path[FILE_NAME_SIZE];
 	struct path * pp;
-	int r = 0;
 
-	if(safe_sprintf(path, "%s/block", sysfs_path)) {
+	if (!devname)
+		return 0;
+
+	if (blacklist(conf->blist_devnode, devname))
+		return 0;
+
+	if(safe_sprintf(path, "%s/block/%s/device", sysfs_path,
+			devname)) {
 		condlog(0, "path too small");
 		return 1;
 	}
-	sdir = sysfs_open_directory(path);
+			
+	if (!filepresent(path))
+		return 0;
+
+	pp = find_path_by_dev(pathvec, devname);
+
+	if (!pp) {
+		pp = store_pathinfo(pathvec, conf->hwtable,
+				    devname, flag);
+		return (pp ? 0 : 1);
+	}
+	return pathinfo(pp, conf->hwtable, flag);
+}
 
-	if (!sdir)
+int
+path_discovery (vector pathvec, struct config * conf, int flag)
+{
+	struct dlist * ls;
+	struct sysfs_class * class;
+	struct sysfs_class_device * dev;
+	int r = 1;
+
+	if (!(class = sysfs_open_class("block")))
 		return 1;
 
-	sysfs_read_directory(sdir);
+	if (!(ls = sysfs_get_class_devices(class)))
+		goto out;
 
-	dlist_for_each_data(sdir->subdirs, devp, struct sysfs_directory) {
-		if (!devp)
-			continue;
+	r = 0;
 
-		if (blacklist(conf->blist, devp->name))
-			continue;
+	dlist_for_each_data(ls, dev, struct sysfs_class_device)
+		r += path_discover(pathvec, conf, dev->name, flag);
 
-		if(safe_sprintf(path, "%s/block/%s/device", sysfs_path,
-				devp->name)) {
-			condlog(0, "path too small");
-			sysfs_close_directory(sdir);
-			return 1;
-		}
-				
-		if (!filepresent(path))
-			continue;
-
-		pp = find_path_by_dev(pathvec, devp->name);
-
-		if (!pp) {
-			/*
-			 * new path : alloc, store and fetch info
-			 * the caller wants
-			 */
-			if (!store_pathinfo(pathvec, conf->hwtable,
-					   devp->name, flag)) {
-				r++;
-				continue;
-			}
-		} else {
-			/*
-			 * path already known :
-			 * refresh only what the caller wants
-			 */
-			if (pathinfo(pp, conf->hwtable, flag)) {
-				r++;
-				continue;
-			}
-		}
-	}
-	sysfs_close_directory(sdir);
+out:
+	sysfs_close_class(class);
 	return r;
 }
 
@@ -149,14 +141,13 @@
 	return 0;
 }
 #endif
-			
+
 #define declare_sysfs_get_str(fname, fmt) \
 extern int \
 sysfs_get_##fname (char * sysfs_path, char * dev, char * buff, int len) \
 { \
+	struct sysfs_attribute * attr; \
 	char attr_path[SYSFS_PATH_SIZE]; \
-	char attr_buff[SYSFS_PATH_SIZE]; \
-	int attr_len; \
 \
 	if (safe_sprintf(attr_path, fmt, sysfs_path, dev)) \
 		return 1; \
@@ -164,51 +155,61 @@
 	if (wait_for_file(attr_path)) \
 		return 1; \
 \
-	if (0 > sysfs_read_attribute_value(attr_path, attr_buff, sizeof(attr_buff))) \
+	if (!(attr = sysfs_open_attribute(attr_path))) \
 		return 1; \
 \
-	attr_len = strlen(attr_buff); \
-	if (attr_len < 2 || attr_len - 1 > len) \
-		return 1; \
+	if (0 > sysfs_read_attribute(attr)) \
+		goto out; \
 \
-	strncpy(buff, attr_buff, attr_len - 1); \
-	buff[attr_len - 1] = '\0'; \
+	if (attr->len < 2 || attr->len - 1 > len) \
+		goto out; \
+\
+	strncpy(buff, attr->value, attr->len - 1); \
+	buff[attr->len - 1] = '\0'; \
+	sysfs_close_attribute(attr); \
 	return 0; \
+out: \
+	sysfs_close_attribute(attr); \
+	return 1; \
 }
 
+declare_sysfs_get_str(devtype, "%s/block/%s/device/devtype");
+declare_sysfs_get_str(cutype, "%s/block/%s/device/cutype");
 declare_sysfs_get_str(vendor, "%s/block/%s/device/vendor");
 declare_sysfs_get_str(model, "%s/block/%s/device/model");
 declare_sysfs_get_str(rev, "%s/block/%s/device/rev");
 declare_sysfs_get_str(dev, "%s/block/%s/dev");
 
-#define declare_sysfs_get_val(fname, fmt) \
-extern unsigned long long  \
-sysfs_get_##fname (char * sysfs_path, char * dev) \
-{ \
-	char attr_path[SYSFS_PATH_SIZE]; \
-	char attr_buff[SYSFS_PATH_SIZE]; \
-	int r; \
-	unsigned long long val; \
-\
-	if (safe_sprintf(attr_path, fmt, sysfs_path, dev)) \
-		return 0; \
-\
-	if (wait_for_file(attr_path)) \
-		return 0; \
-\
-	if (0 > sysfs_read_attribute_value(attr_path, attr_buff, sizeof(attr_buff))) \
-		return 0; \
-\
-	r = sscanf(attr_buff, "%llu\n", &val); \
-\
-	if (r != 1) \
-		return 0; \
-	else \
-		return (val); \
-}
+int
+sysfs_get_size (char * sysfs_path, char * dev, unsigned long long * size)
+{
+	struct sysfs_attribute * attr;
+	char attr_path[SYSFS_PATH_SIZE];
+	int r;
+
+	if (safe_sprintf(attr_path, "%s/block/%s/size", sysfs_path, dev))
+		return 1;
+
+	attr = sysfs_open_attribute(attr_path);
+
+	if (!attr)
+		return 1;
+
+	if (0 > sysfs_read_attribute(attr))
+		goto out;
 
-declare_sysfs_get_val(size, "%s/block/%s/size");
+	r = sscanf(attr->value, "%llu\n", size);
+	sysfs_close_attribute(attr);
 
+	if (r != 1)
+		return 1;
+
+	return 0;
+out:
+	sysfs_close_attribute(attr);
+	return 1;
+}
+	
 /*
  * udev might be slow creating node files : wait
  */
@@ -233,49 +234,56 @@
 extern int
 devt2devname (char *devname, char *devt)
 {
-	struct sysfs_directory * sdir;
-	struct sysfs_directory * devp;
-	char block_path[FILE_NAME_SIZE];
+	struct dlist * ls;
 	char attr_path[FILE_NAME_SIZE];
-	char attr_value[16];
-	int len;
+	char block_path[FILE_NAME_SIZE];
+	struct sysfs_attribute * attr;
+	struct sysfs_class * class;
+	struct sysfs_class_device * dev;
 
 	if(safe_sprintf(block_path, "%s/block", sysfs_path)) {
 		condlog(0, "block_path too small");
 		return 1;
 	}
-	sdir = sysfs_open_directory(block_path);
-	sysfs_read_directory(sdir);
+	if (!(class = sysfs_open_class("block")))
+		return 1;
+
+	if (!(ls = sysfs_get_class_devices(class)))
+		goto err;
 
-	dlist_for_each_data (sdir->subdirs, devp, struct sysfs_directory) {
+	dlist_for_each_data(ls, dev, struct sysfs_class_device) {
 		if(safe_sprintf(attr_path, "%s/%s/dev",
-				block_path, devp->name)) {
+				block_path, dev->name)) {
 			condlog(0, "attr_path too small");
 			goto err;
 		}
-		sysfs_read_attribute_value(attr_path, attr_value,
-					   sizeof(attr_value));
+		if (!(attr = sysfs_open_attribute(attr_path)))
+			goto err;
 
-		len = strlen(attr_value);
+		if (sysfs_read_attribute(attr))
+			goto err1;
 
 		/* discard newline */
-		if (len > 1) len--;
+		if (attr->len > 1) attr->len--;
 
-		if (strlen(devt) == len &&
-		    strncmp(attr_value, devt, len) == 0) {
+		if (strlen(devt) == attr->len &&
+		    strncmp(attr->value, devt, attr->len) == 0) {
 			if(safe_sprintf(attr_path, "%s/%s",
-					block_path, devp->name)) {
+					block_path, dev->name)) {
 				condlog(0, "attr_path too small");
-				goto err;
+				goto err1;
 			}
 			sysfs_get_name_from_path(attr_path, devname,
 						 FILE_NAME_SIZE);
-			sysfs_close_directory(sdir);
+			sysfs_close_attribute(attr);
+			sysfs_close_class(class);
 			return 0;
 		}
 	}
+err1:
+	sysfs_close_attribute(attr);
 err:
-	sysfs_close_directory(sdir);
+	sysfs_close_class(class);
 	return 1;
 }
 
@@ -334,8 +342,8 @@
 int
 get_serial (char * str, int fd)
 {
-        int len;
-        char buff[MX_ALLOC_LEN + 1];
+        int len = 0;
+        char buff[MX_ALLOC_LEN + 1] = {0};
 
 	if (fd < 0)
                 return 0;
@@ -351,14 +359,14 @@
         return 0;
 }
 
-static void
-sysfs_get_bus (char * sysfs_path, struct path * curpath)
+static int
+sysfs_get_bus (char * sysfs_path, struct path * pp)
 {
 	struct sysfs_device *sdev;
 	char attr_path[FILE_NAME_SIZE];
 	char attr_buff[FILE_NAME_SIZE];
 
-	curpath->bus = SYSFS_BUS_UNDEF;
+	pp->bus = SYSFS_BUS_UNDEF;
 
 	/*
 	 * This is ugly : we should be able to do a simple
@@ -366,55 +374,79 @@
 	 * won't work
 	 */
 	if(safe_sprintf(attr_path, "%s/block/%s/device",
-			sysfs_path, curpath->dev)) {
+			sysfs_path, pp->dev)) {
 		condlog(0, "attr_path too small");
-		return;
+		return 1;
 	}
 
 	if (0 > sysfs_get_link(attr_path, attr_buff, sizeof(attr_buff)))
-		return;
+		return 1;
+
+#if DAEMON
+	int loop = WAIT_MAX_SECONDS * WAIT_LOOP_PER_SECOND;
 
+	while (loop--) {
+		sdev = sysfs_open_device_path(attr_buff);
+
+		if (strlen(sdev->bus))
+			break;
+
+		sysfs_close_device(sdev);
+		usleep(1000 * 1000 / WAIT_LOOP_PER_SECOND);
+	}
+#else
 	sdev = sysfs_open_device_path(attr_buff);
+#endif
 
 	if (!strncmp(sdev->bus, "scsi", 4))
-		curpath->bus = SYSFS_BUS_SCSI;
+		pp->bus = SYSFS_BUS_SCSI;
 	else if (!strncmp(sdev->bus, "ide", 3))
-		curpath->bus = SYSFS_BUS_IDE;
+		pp->bus = SYSFS_BUS_IDE;
+	else if (!strncmp(sdev->bus, "ccw", 3))
+		pp->bus = SYSFS_BUS_CCW;
+	else
+		return 1;
 
 	sysfs_close_device(sdev);
 
-	return;
+	return 0;
 }
 
 static int
-scsi_sysfs_pathinfo (struct path * curpath)
+scsi_sysfs_pathinfo (struct path * pp)
 {
 	char attr_path[FILE_NAME_SIZE];
 	char attr_buff[FILE_NAME_SIZE];
+	struct sysfs_attribute * attr;
 
-	if (sysfs_get_vendor(sysfs_path, curpath->dev,
-			     curpath->vendor_id, SCSI_VENDOR_SIZE))
+	if (sysfs_get_vendor(sysfs_path, pp->dev,
+			     pp->vendor_id, SCSI_VENDOR_SIZE))
 		return 1;
 
-	condlog(3, "vendor = %s", curpath->vendor_id);
+	condlog(3, "%s: vendor = %s", pp->dev, pp->vendor_id);
 
-	if (sysfs_get_model(sysfs_path, curpath->dev,
-			    curpath->product_id, SCSI_PRODUCT_SIZE))
+	if (sysfs_get_model(sysfs_path, pp->dev,
+			    pp->product_id, SCSI_PRODUCT_SIZE))
 		return 1;
 
-	condlog(3, "product = %s", curpath->product_id);
+	condlog(3, "%s: product = %s", pp->dev, pp->product_id);
 
-	if (sysfs_get_rev(sysfs_path, curpath->dev,
-			  curpath->rev, SCSI_REV_SIZE))
+	if (sysfs_get_rev(sysfs_path, pp->dev,
+			  pp->rev, SCSI_REV_SIZE))
 		return 1;
 
-	condlog(3, "rev = %s", curpath->rev);
+	condlog(3, "%s: rev = %s", pp->dev, pp->rev);
+
+	/*
+	 * set the hwe configlet pointer
+	 */
+	pp->hwe = find_hwe(conf->hwtable, pp->vendor_id, pp->product_id);
 
 	/*
 	 * host / bus / target / lun
 	 */
 	if(safe_sprintf(attr_path, "%s/block/%s/device",
-			sysfs_path, curpath->dev)) {
+			sysfs_path, pp->dev)) {
 		condlog(0, "attr_path too small");
 		return 1;
 	}
@@ -424,15 +456,16 @@
 	basename(attr_buff, attr_path);
 
 	sscanf(attr_path, "%i:%i:%i:%i",
-			&curpath->sg_id.host_no,
-			&curpath->sg_id.channel,
-			&curpath->sg_id.scsi_id,
-			&curpath->sg_id.lun);
-	condlog(3, "h:b:t:l = %i:%i:%i:%i",
-			curpath->sg_id.host_no,
-			curpath->sg_id.channel,
-			curpath->sg_id.scsi_id,
-			curpath->sg_id.lun);
+			&pp->sg_id.host_no,
+			&pp->sg_id.channel,
+			&pp->sg_id.scsi_id,
+			&pp->sg_id.lun);
+	condlog(3, "%s: h:b:t:l = %i:%i:%i:%i",
+			pp->dev,
+			pp->sg_id.host_no,
+			pp->sg_id.channel,
+			pp->sg_id.scsi_id,
+			pp->sg_id.lun);
 
 	/*
 	 * target node name
@@ -440,150 +473,209 @@
 	if(safe_sprintf(attr_path,
 			"%s/class/fc_transport/target%i:%i:%i/node_name",
 			sysfs_path,
-			curpath->sg_id.host_no,
-			curpath->sg_id.channel,
-			curpath->sg_id.scsi_id)) {
+			pp->sg_id.host_no,
+			pp->sg_id.channel,
+			pp->sg_id.scsi_id)) {
 		condlog(0, "attr_path too small");
 		return 1;
 	}
-	if (0 <= readattr(attr_path, attr_buff) && strlen(attr_buff) > 0)
-		strncpy(curpath->tgt_node_name, attr_buff,
-			strlen(attr_buff) - 1);
-	condlog(3, "tgt_node_name = %s", curpath->tgt_node_name);
+	if (!(attr = sysfs_open_attribute(attr_path)))
+		return 0;
+
+	if (sysfs_read_attribute(attr))
+		goto err;
+
+	if (attr->len > 0)
+		strncpy(pp->tgt_node_name, attr->value, attr->len - 1);
+
+	condlog(3, "%s: tgt_node_name = %s",
+		pp->dev, pp->tgt_node_name);
 
 	return 0;
+err:
+	sysfs_close_attribute(attr);
+	return 1;
 }
 
 static int
-common_sysfs_pathinfo (struct path * curpath)
+ccw_sysfs_pathinfo (struct path * pp)
 {
-	sysfs_get_bus(sysfs_path, curpath);
-	condlog(3, "bus = %i", curpath->bus);
-
-	if (sysfs_get_dev(sysfs_path, curpath->dev,
-			  curpath->dev_t, BLK_DEV_SIZE))
-		return 1;
+	char attr_path[FILE_NAME_SIZE];
+	char attr_buff[FILE_NAME_SIZE];
 
-	condlog(3, "dev_t = %s", curpath->dev_t);
+	sprintf(pp->vendor_id, "IBM");
 
-	curpath->size = sysfs_get_size(sysfs_path, curpath->dev);
+	condlog(3, "%s: vendor = %s", pp->dev, pp->vendor_id);
 
-	if (curpath->size == 0)
+	if (sysfs_get_devtype(sysfs_path, pp->dev,
+			      attr_buff, FILE_NAME_SIZE))
 		return 1;
 
-	condlog(3, "size = %llu", curpath->size);
+	if (!strncmp(attr_buff, "3370", 4)) {
+		sprintf(pp->product_id,"S/390 DASD FBA");
+	} else if (!strncmp(attr_buff, "9336", 4)) {
+		sprintf(pp->product_id,"S/390 DASD FBA");
+	} else {
+		sprintf(pp->product_id,"S/390 DASD ECKD");
+	}
 
-	return 0;
-}
+	condlog(3, "%s: product = %s", pp->dev, pp->product_id);
 
-extern int
-sysfs_pathinfo(struct path * curpath)
-{
-	if (common_sysfs_pathinfo(curpath))
-		return 1;
+	/*
+	 * set the hwe configlet pointer
+	 */
+	pp->hwe = find_hwe(conf->hwtable, pp->vendor_id, pp->product_id);
 
-	if (curpath->bus == SYSFS_BUS_UNDEF)
-		return 0;
-	else if (curpath->bus == SYSFS_BUS_SCSI)
-		if (scsi_sysfs_pathinfo(curpath))
-			return 1;
+	/*
+	 * host / bus / target / lun
+	 */
+	if(safe_sprintf(attr_path, "%s/block/%s/device",
+			sysfs_path, pp->dev)) {
+		condlog(0, "attr_path too small");
+		return 1;
+	}
+	if (0 > sysfs_get_link(attr_path, attr_buff, sizeof(attr_buff)))
+		return 1;
+	
+	basename(attr_buff, attr_path);
+	pp->sg_id.lun = 0;
+	sscanf(attr_path, "%i.%i.%x",
+			&pp->sg_id.host_no,
+			&pp->sg_id.channel,
+			&pp->sg_id.scsi_id);
+	condlog(3, "%s: h:b:t:l = %i:%i:%i:%i",
+			pp->dev,
+			pp->sg_id.host_no,
+			pp->sg_id.channel,
+			pp->sg_id.scsi_id,
+			pp->sg_id.lun);
 
 	return 0;
 }
 
 static int
-apply_format (char * string, char * cmd, struct path * pp)
+common_sysfs_pathinfo (struct path * pp)
 {
-	char * pos;
-	char * dst;
-	char * p;
-	int len;
-	int myfree;
-
-	if (!string)
+	if (sysfs_get_bus(sysfs_path, pp))
 		return 1;
 
-	if (!cmd)
+	condlog(3, "%s: bus = %i", pp->dev, pp->bus);
+
+	if (sysfs_get_dev(sysfs_path, pp->dev,
+			  pp->dev_t, BLK_DEV_SIZE))
 		return 1;
 
-	dst = cmd;
-	p = dst;
-	pos = strchr(string, '%');
-	myfree = CALLOUT_MAX_SIZE;
+	condlog(3, "%s: dev_t = %s", pp->dev, pp->dev_t);
 
-	if (!pos) {
-		strcpy(dst, string);
-		return 0;
-	}
+	if (sysfs_get_size(sysfs_path, pp->dev, &pp->size))
+		return 1;
+
+	condlog(3, "%s: size = %llu", pp->dev, pp->size);
 
-	len = (int) (pos - string) + 1;
-	myfree -= len;
+	return 0;
+}
 
-	if (myfree < 2)
+extern int
+sysfs_pathinfo(struct path * pp)
+{
+	if (common_sysfs_pathinfo(pp))
 		return 1;
 
-	snprintf(p, len, "%s", string);
-	p += len - 1;
-	pos++;
+	if (pp->bus == SYSFS_BUS_UNDEF)
+		return 0;
+	else if (pp->bus == SYSFS_BUS_SCSI) {
+		if (scsi_sysfs_pathinfo(pp))
+			return 1;
+	} else if (pp->bus == SYSFS_BUS_CCW) {
+		if (ccw_sysfs_pathinfo(pp))
+			return 1;
+	}
+	return 0;
+}
 
-	switch (*pos) {
-	case 'n':
-		len = strlen(pp->dev) + 1;
-		myfree -= len;
+static int
+scsi_ioctl_pathinfo (struct path * pp, int mask)
+{
+	if (mask & DI_SERIAL) {
+		get_serial(pp->serial, pp->fd);
+		condlog(3, "%s: serial = %s", pp->dev, pp->serial);
+	}
 
-		if (myfree < 2)
-			return 1;
+	return 0;
+}
 
-		snprintf(p, len, "%s", pp->dev);
-		p += len - 1;
-		break;
-	case 'd':
-		len = strlen(pp->dev_t) + 1;
-		myfree -= len;
+static int
+get_state (struct path * pp)
+{
+	struct checker * c = &pp->checker;
 
-		if (myfree < 2)
+	if (!checker_selected(c)) {
+		select_checker(pp);
+		if (!checker_selected(c))
+			return 1;
+		checker_set_fd(c, pp->fd);
+		if (checker_init(c))
 			return 1;
-
-		snprintf(p, len, "%s", pp->dev_t);
-		p += len - 1;
-		break;
-	default:
-		break;
 	}
-	pos++;
-
-	if (!*pos)
-		return 0;
+	pp->state = checker_check(c);
+	condlog(3, "%s: state = %i", pp->dev, pp->state);
+	if (pp->state == PATH_DOWN)
+		condlog(2, "%s: checker msg is \"%s\"",
+			pp->dev, checker_message(c));
+	return 0;
+}
 
-	len = strlen(pos) + 1;
-	myfree -= len;
+static int
+get_prio (struct path * pp)
+{
+	char buff[CALLOUT_MAX_SIZE];
+	char prio[16];
 
-	if (myfree < 2)
+	if (!pp->getprio_selected) {
+		select_getprio(pp);
+		pp->getprio_selected = 1;
+	}
+	if (!pp->getprio) {
+		pp->priority = 1;
+	} else if (apply_format(pp->getprio, &buff[0], pp)) {
+		condlog(0, "error formatting prio callout command");
+		pp->priority = -1;
+		return 1;
+	} else if (execute_program(buff, prio, 16)) {
+		condlog(0, "error calling out %s", buff);
+		pp->priority = -1;
 		return 1;
+	} else
+		pp->priority = atoi(prio);
 
-	snprintf(p, len, "%s", pos);
-	condlog(3, "reformated callout = %s", dst);
+	condlog(3, "%s: prio = %u", pp->dev, pp->priority);
 	return 0;
 }
 
 static int
-scsi_ioctl_pathinfo (struct path * pp, int mask)
+get_uid (struct path * pp)
 {
-	if (mask & DI_SERIAL) {
-		get_serial(pp->serial, pp->fd);
-		condlog(3, "serial = %s", pp->serial);
-	}
+	char buff[CALLOUT_MAX_SIZE];
 
+	if (!pp->getuid)
+		select_getuid(pp);
+
+	if (apply_format(pp->getuid, &buff[0], pp)) {
+		condlog(0, "error formatting uid callout command");
+		memset(pp->wwid, 0, WWID_SIZE);
+	} else if (execute_program(buff, pp->wwid, WWID_SIZE)) {
+		condlog(0, "error calling out %s", buff);
+		memset(pp->wwid, 0, WWID_SIZE);
+		return 1;
+	}
+	condlog(3, "%s: uid = %s (callout)", pp->dev ,pp->wwid);
 	return 0;
 }
 
 extern int
 pathinfo (struct path *pp, vector hwtable, int mask)
 {
-	char buff[CALLOUT_MAX_SIZE];
-	char prio[16];
-
-	condlog(3, "===== path info %s (mask 0x%x) =====", pp->dev, mask);
+	condlog(3, "%s: mask = 0x%x", pp->dev, mask);
 
 	/*
 	 * fetch info available in sysfs
@@ -598,72 +690,26 @@
 		pp->fd = opennode(pp->dev, O_RDONLY);
 
 	if (pp->fd < 0)
-		goto out;
+		goto blank;
 
 	if (pp->bus == SYSFS_BUS_SCSI &&
 	    scsi_ioctl_pathinfo(pp, mask))
-		goto out;
-
-	/* get and store hwe pointer */
-	pp->hwe = find_hwe(hwtable, pp->vendor_id, pp->product_id);
-
-	/*
-	 * get path state, no message collection, no context
-	 */
-	if (mask & DI_CHECKER) {
-		if (!pp->checkfn)
-			select_checkfn(pp);
+		goto blank;
 
-		pp->state = pp->checkfn(pp->fd, NULL, NULL);
-		condlog(3, "state = %i", pp->state);
-	}
+	if (mask & DI_CHECKER && get_state(pp))
+		goto blank;
 	
-	/*
-	 * get path prio
-	 */
-	if (mask & DI_PRIO) {
-		if (!pp->getprio)
-			select_getprio(pp);
-
-		if (!pp->getprio) {
-			pp->priority = 1;
-		} else if (apply_format(pp->getprio, &buff[0], pp)) {
-			condlog(0, "error formatting prio callout command");
-			pp->priority = -1;
-		} else if (execute_program(buff, prio, 16)) {
-			condlog(0, "error calling out %s", buff);
-			pp->priority = -1;
-		} else
-			pp->priority = atoi(prio);
+	if (mask & DI_PRIO && pp->state != PATH_DOWN)
+		get_prio(pp);
 
-		condlog(3, "prio = %u", pp->priority);
-	}
-
-	/*
-	 * get path uid
-	 */
-	if (mask & DI_WWID && !strlen(pp->wwid)) {
-		if (!pp->getuid)
-			select_getuid(pp);
-
-		if (apply_format(pp->getuid, &buff[0], pp)) {
-			condlog(0, "error formatting uid callout command");
-			memset(pp->wwid, 0, WWID_SIZE);
-		} else if (execute_program(buff, pp->wwid, WWID_SIZE)) {
-			condlog(0, "error calling out %s", buff);
-			memset(pp->wwid, 0, WWID_SIZE);
-		}
-		condlog(3, "uid = %s (callout)", pp->wwid);
-	}
-	else if (strlen(pp->wwid))
-		condlog(3, "uid = %s (cache)", pp->wwid);
+	if (mask & DI_WWID && !strlen(pp->wwid))
+		get_uid(pp);
 
 	return 0;
 
-out:
+blank:
 	/*
 	 * Recoverable error, for example faulty or offline path
-	 * Set up safe defaults, don't trust the cache
 	 */
 	memset(pp->wwid, 0, WWID_SIZE);
 	pp->state = PATH_DOWN;

Modified: multipath-tools/trunk/libmultipath/discovery.h
==============================================================================
--- multipath-tools/trunk/libmultipath/discovery.h	(original)
+++ multipath-tools/trunk/libmultipath/discovery.h	Mon Mar 13 15:16:41 2006
@@ -26,7 +26,7 @@
 int sysfs_get_rev (char * sysfs_path, char * dev, char * buff, int len);
 int sysfs_get_dev (char * sysfs_path, char * dev, char * buff, int len);
 
-unsigned long long sysfs_get_size (char * sysfs_path, char * dev);
+int sysfs_get_size (char * sysfs_path, char * dev, unsigned long long *);
 int path_discovery (vector pathvec, struct config * conf, int flag);
 
 void basename (char *, char *);

Modified: multipath-tools/trunk/libmultipath/dmparser.c
==============================================================================
--- multipath-tools/trunk/libmultipath/dmparser.c	(original)
+++ multipath-tools/trunk/libmultipath/dmparser.c	Mon Mar 13 15:16:41 2006
@@ -1,12 +1,14 @@
 /*
- * Christophe Varoqui (2004)
- * This code is GPLv2, see license file
- *
+ * Copyright (c) 2004, 2005 Christophe Varoqui
+ * Copyright (c) 2005 Stefan Bader, IBM
+ * Copyright (c) 2005 Edward Goggin, EMC
  */
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 
+#include <checkers.h>
+
 #include "vector.h"
 #include "memory.h"
 #include "structs.h"
@@ -42,6 +44,67 @@
 	return 0;
 }
 
+/*
+ * Transforms the path group vector into a proper device map string
+ */
+int
+assemble_map (struct multipath * mp)
+{
+	int i, j;
+	int shift, freechar;
+	int minio;
+	char * p;
+	struct pathgroup * pgp;
+	struct path * pp;
+
+	minio = mp->minio;
+	p = mp->params;
+	freechar = sizeof(mp->params);
+	
+	shift = snprintf(p, freechar, "%s %s %i %i",
+			 mp->features, mp->hwhandler,
+			 VECTOR_SIZE(mp->pg), mp->bestpg);
+
+	if (shift >= freechar) {
+		fprintf(stderr, "mp->params too small\n");
+		return 1;
+	}
+	p += shift;
+	freechar -= shift;
+	
+	vector_foreach_slot (mp->pg, pgp, i) {
+		pgp = VECTOR_SLOT(mp->pg, i);
+		shift = snprintf(p, freechar, " %s %i 1", mp->selector,
+				 VECTOR_SIZE(pgp->paths));
+		if (shift >= freechar) {
+			fprintf(stderr, "mp->params too small\n");
+			return 1;
+		}
+		p += shift;
+		freechar -= shift;
+
+		vector_foreach_slot (pgp->paths, pp, j) {
+			if (mp->rr_weight == RR_WEIGHT_PRIO && pp->priority)
+				minio *= pp->priority;
+
+			shift = snprintf(p, freechar, " %s %d",
+					 pp->dev_t, minio);
+			if (shift >= freechar) {
+				fprintf(stderr, "mp->params too small\n");
+				return 1;
+			}
+			p += shift;
+			freechar -= shift;
+		}
+	}
+	if (freechar < 1) {
+		fprintf(stderr, "mp->params too small\n");
+		return 1;
+	}
+	snprintf(p, 1, "\n");
+	return 0;
+}
+
 extern int
 disassemble_map (vector pathvec, char * params, struct multipath * mpp)
 {
@@ -210,6 +273,11 @@
 					goto out1;
 
 				strncpy(pp->dev_t, word, BLK_DEV_SIZE);
+
+#ifndef DAEMON
+				if (store_path(pathvec, pp))
+					goto out;
+#endif
 			}
 			FREE(word);
 
@@ -234,7 +302,19 @@
 			pp->pgindex = i + 1;
 
 			for (k = 0; k < num_paths_args; k++)
-				p += get_word(p, NULL);
+				if (k == 0 && !strncmp(mpp->selector,
+						       "round-robin", 11)) {
+					p += get_word(p, &word);
+					mpp->minio = atoi(word);
+
+					if (mpp->rr_weight)
+						mpp->minio /= mpp->rr_weight;
+
+					FREE(word);
+				}
+				else
+					p += get_word(p, NULL);
+
 		}
 	}
 	return 0;

Modified: multipath-tools/trunk/libmultipath/dmparser.h
==============================================================================
--- multipath-tools/trunk/libmultipath/dmparser.h	(original)
+++ multipath-tools/trunk/libmultipath/dmparser.h	Mon Mar 13 15:16:41 2006
@@ -1,2 +1,3 @@
+int assemble_map (struct multipath *);
 int disassemble_map (vector, char *, struct multipath *);
 int disassemble_status (char *, struct multipath *);

Modified: multipath-tools/trunk/libmultipath/hwtable.c
==============================================================================
--- multipath-tools/trunk/libmultipath/hwtable.c	(original)
+++ multipath-tools/trunk/libmultipath/hwtable.c	Mon Mar 13 15:16:41 2006
@@ -1,50 +1,470 @@
 #include <stdio.h>
 
+#include <checkers.h>
+
 #include "vector.h"
 #include "defaults.h"
 #include "structs.h"
 #include "config.h"
 #include "pgpolicies.h"
 
+/*
+ * Tuning suggestions on these parameters should go to
+ * dm-devel at redhat.com
+ * 
+ * You are welcome to claim maintainership over a controler
+ * family. Please mail the currently enlisted maintainer and
+ * the upstream package maintainer.
+ */
+static struct hwentry default_hw[] = {
+	/*
+	 * StorageWorks controler family
+	 *
+	 * Maintainer : Christophe Varoqui
+	 * Mail : christophe.varoqui at free.fr
+	 */
+	{
+		.vendor        = "3PARdata",
+		.product       = "VV",
+		.getuid        = DEFAULT_GETUID,
+		.getprio       = NULL,
+		.features      = DEFAULT_FEATURES,
+		.hwhandler     = DEFAULT_HWHANDLER,
+		.selector      = DEFAULT_SELECTOR,
+		.pgpolicy      = MULTIBUS,
+		.pgfailback    = FAILBACK_UNDEF,
+		.rr_weight     = RR_WEIGHT_NONE,
+		.no_path_retry = NO_PATH_RETRY_UNDEF,
+		.minio         = DEFAULT_MINIO,
+		.checker_name  = DEFAULT_CHECKER,
+	},
+	{
+		.vendor        = "DEC",
+		.product       = "HSG80",
+		.getuid        = DEFAULT_GETUID,
+		.getprio       = NULL,
+		.features      = DEFAULT_FEATURES,
+		.hwhandler     = "1 hp_sw",
+		.selector      = DEFAULT_SELECTOR,
+		.pgpolicy      = GROUP_BY_SERIAL,
+		.pgfailback    = FAILBACK_UNDEF,
+		.rr_weight     = RR_WEIGHT_NONE,
+		.no_path_retry = NO_PATH_RETRY_UNDEF,
+		.minio         = DEFAULT_MINIO,
+		.checker_name  = HP_SW,
+	},
+	{
+		.vendor        = "{COMPAQ,HP}",
+		.product       = "{MSA,HSV}1*",
+		.getuid        = DEFAULT_GETUID,
+		.getprio       = NULL,
+		.features      = DEFAULT_FEATURES,
+		.hwhandler     = "1 hp_sw",
+		.selector      = DEFAULT_SELECTOR,
+		.pgpolicy      = GROUP_BY_SERIAL,
+		.pgfailback    = FAILBACK_UNDEF,
+		.rr_weight     = RR_WEIGHT_NONE,
+		.no_path_retry = NO_PATH_RETRY_UNDEF,
+		.minio         = DEFAULT_MINIO,
+		.checker_name  = HP_SW,
+	},
+	{
+		.vendor        = "HP",
+		.product       = "HSV2*",
+		.getuid        = DEFAULT_GETUID,
+		.getprio       = NULL,
+		.features      = DEFAULT_FEATURES,
+		.hwhandler     = DEFAULT_HWHANDLER,
+		.selector      = DEFAULT_SELECTOR,
+		.pgpolicy      = MULTIBUS,
+		.pgfailback    = FAILBACK_UNDEF,
+		.rr_weight     = RR_WEIGHT_NONE,
+		.no_path_retry = NO_PATH_RETRY_UNDEF,
+		.minio         = DEFAULT_MINIO,
+		.checker_name  = READSECTOR0,
+	},
+	{
+		.vendor        = "HP",
+		.product       = "DF[456]00",
+		.getuid        = DEFAULT_GETUID,
+		.getprio       = NULL,
+		.features      = DEFAULT_FEATURES,
+		.hwhandler     = DEFAULT_HWHANDLER,
+		.selector      = DEFAULT_SELECTOR,
+		.pgpolicy      = MULTIBUS,
+		.pgfailback    = FAILBACK_UNDEF,
+		.rr_weight     = RR_WEIGHT_NONE,
+		.no_path_retry = NO_PATH_RETRY_UNDEF,
+		.minio         = DEFAULT_MINIO,
+		.checker_name  = READSECTOR0,
+	},
+	/*
+	 * DDN controler family
+	 *
+	 * Maintainer : Christophe Varoqui
+	 * Mail : christophe.varoqui at free.fr
+	 */
+	{
+		.vendor        = "DDN",
+		.product       = "SAN DataDirector",
+		.getuid        = DEFAULT_GETUID,
+		.getprio       = NULL,
+		.features      = DEFAULT_FEATURES,
+		.hwhandler     = DEFAULT_HWHANDLER,
+		.selector      = DEFAULT_SELECTOR,
+		.pgpolicy      = MULTIBUS,
+		.pgfailback    = FAILBACK_UNDEF,
+		.rr_weight     = RR_WEIGHT_NONE,
+		.no_path_retry = NO_PATH_RETRY_UNDEF,
+		.minio         = DEFAULT_MINIO,
+		.checker_name  = READSECTOR0,
+	},
+	/*
+	 * EMC / Clariion controler family
+	 *
+	 * Maintainer : Edward Goggin, EMC
+	 * Mail : egoggin at emc.com
+	 */
+	{
+		.vendor        = "EMC",
+		.product       = "SYMMETRIX",
+		.getuid        = "/sbin/scsi_id -g -u -ppre-spc3-83 -s /block/%n",
+		.getprio       = NULL,
+		.features      = DEFAULT_FEATURES,
+		.hwhandler     = DEFAULT_HWHANDLER,
+		.selector      = DEFAULT_SELECTOR,
+		.pgpolicy      = MULTIBUS,
+		.pgfailback    = FAILBACK_UNDEF,
+		.rr_weight     = RR_WEIGHT_NONE,
+		.no_path_retry = NO_PATH_RETRY_UNDEF,
+		.minio         = DEFAULT_MINIO,
+		.checker_name  = READSECTOR0,
+	},
+	{
+		.vendor        = "DGC",
+		.product       = "*",
+		.bl_product    = "LUNZ",
+		.getuid        = DEFAULT_GETUID,
+		.getprio       = "/sbin/mpath_prio_emc /dev/%n",
+		.features      = "1 queue_if_no_path",
+		.hwhandler     = "1 emc",
+		.selector      = DEFAULT_SELECTOR,
+		.pgpolicy      = GROUP_BY_PRIO,
+		.pgfailback    = -FAILBACK_IMMEDIATE,
+		.rr_weight     = RR_WEIGHT_NONE,
+		.no_path_retry = (300 / DEFAULT_CHECKINT),
+		.minio         = DEFAULT_MINIO,
+		.checker_name  = EMC_CLARIION,
+	},
+	/*
+	 * Fujitsu controler family
+	 *
+	 * Maintainer : Christophe Varoqui
+	 * Mail : christophe.varoqui at free.fr
+	 */
+	{
+		.vendor        = "FSC",
+		.product       = "CentricStor",
+		.getuid        = DEFAULT_GETUID,
+		.getprio       = NULL,
+		.features      = DEFAULT_FEATURES,
+		.hwhandler     = DEFAULT_HWHANDLER,
+		.selector      = DEFAULT_SELECTOR,
+		.pgpolicy      = GROUP_BY_SERIAL,
+		.pgfailback    = FAILBACK_UNDEF,
+		.rr_weight     = RR_WEIGHT_NONE,
+		.no_path_retry = NO_PATH_RETRY_UNDEF,
+		.minio         = DEFAULT_MINIO,
+		.checker_name  = READSECTOR0,
+	},
+	/*
+	 * Hitachi controler family
+	 *
+	 * Maintainer : Christophe Varoqui
+	 * Mail : christophe.varoqui at free.fr
+	 */
+	{
+		.vendor        = "HITACHI",
+		.product       = "{A6189A,OPEN-}",
+		.getuid        = DEFAULT_GETUID,
+		.getprio       = NULL,
+		.features      = DEFAULT_FEATURES,
+		.hwhandler     = DEFAULT_HWHANDLER,
+		.selector      = DEFAULT_SELECTOR,
+		.pgpolicy      = MULTIBUS,
+		.pgfailback    = FAILBACK_UNDEF,
+		.rr_weight     = RR_WEIGHT_NONE,
+		.no_path_retry = NO_PATH_RETRY_UNDEF,
+		.minio         = DEFAULT_MINIO,
+		.checker_name  = READSECTOR0,
+	},
+	/*
+	 * IBM controler family
+	 *
+	 * Maintainer : Hannes Reinecke, Suse
+	 * Mail : hare at suse.de
+	 */
+	{
+		.vendor        = "IBM",
+		.product       = "ProFibre 4000R",
+		.getuid        = DEFAULT_GETUID,
+		.getprio       = NULL,
+		.features      = DEFAULT_FEATURES,
+		.hwhandler     = DEFAULT_HWHANDLER,
+		.selector      = DEFAULT_SELECTOR,
+		.pgpolicy      = MULTIBUS,
+		.pgfailback    = FAILBACK_UNDEF,
+		.rr_weight     = RR_WEIGHT_NONE,
+		.no_path_retry = NO_PATH_RETRY_UNDEF,
+		.minio         = DEFAULT_MINIO,
+		.checker_name  = READSECTOR0,
+	},
+	{
+		/* IBM DS4100 / FAStT100 */
+		.vendor        = "IBM",
+		.product       = "1742",
+		.getuid        = DEFAULT_GETUID,
+		.getprio       = "/sbin/mpath_prio_tpc /dev/%n",
+		.features      = DEFAULT_FEATURES,
+		.hwhandler     = DEFAULT_HWHANDLER,
+		.selector      = DEFAULT_SELECTOR,
+		.pgpolicy      = GROUP_BY_PRIO,
+		.pgfailback    = -FAILBACK_IMMEDIATE,
+		.rr_weight     = RR_WEIGHT_NONE,
+		.no_path_retry = NO_PATH_RETRY_UNDEF,
+		.minio         = DEFAULT_MINIO,
+		.checker_name  = TUR,
+	},
+	{
+		/* IBM DS4200 / FAStT200 */
+		.vendor        = "IBM",
+		.product       = "3542",
+		.getuid        = DEFAULT_GETUID,
+		.getprio       = NULL,
+		.features      = DEFAULT_FEATURES,
+		.hwhandler     = DEFAULT_HWHANDLER,
+		.selector      = DEFAULT_SELECTOR,
+		.pgpolicy      = GROUP_BY_SERIAL,
+		.pgfailback    = FAILBACK_UNDEF,
+		.rr_weight     = RR_WEIGHT_NONE,
+		.no_path_retry = NO_PATH_RETRY_UNDEF,
+		.minio         = DEFAULT_MINIO,
+		.checker_name  = TUR,
+	},
+	{
+		/* IBM ESS F20 aka Shark */
+		.vendor        = "IBM",
+		.product       = "2105F20",
+		.getuid        = DEFAULT_GETUID,
+		.getprio       = NULL,
+		.features      = "1 queue_if_no_path",
+		.hwhandler     = DEFAULT_HWHANDLER,
+		.selector      = DEFAULT_SELECTOR,
+		.pgpolicy      = GROUP_BY_SERIAL,
+		.pgfailback    = FAILBACK_UNDEF,
+		.rr_weight     = RR_WEIGHT_NONE,
+		.no_path_retry = NO_PATH_RETRY_UNDEF,
+		.minio         = DEFAULT_MINIO,
+		.checker_name  = TUR,
+	},
+	{
+		/* IBM DS6000 / SAN Volume Controller */
+		.vendor        = "IBM",
+		.product       = "{1750500,2145}",
+		.getuid        = DEFAULT_GETUID,
+		.getprio       = "/sbin/mpath_prio_alua /dev/%n",
+		.features      = "1 queue_if_no_path",
+		.hwhandler     = DEFAULT_HWHANDLER,
+		.selector      = DEFAULT_SELECTOR,
+		.pgpolicy      = GROUP_BY_PRIO,
+		.pgfailback    = -FAILBACK_IMMEDIATE,
+		.rr_weight     = RR_WEIGHT_NONE,
+		.no_path_retry = NO_PATH_RETRY_UNDEF,
+		.minio         = DEFAULT_MINIO,
+		.checker_name  = TUR,
+	},
+	{
+		/* IBM DS8000 */
+		.vendor        = "IBM",
+		.product       = "2107900",
+		.getuid        = DEFAULT_GETUID,
+		.getprio       = NULL,
+		.features      = "1 queue_if_no_path",
+		.hwhandler     = DEFAULT_HWHANDLER,
+		.selector      = DEFAULT_SELECTOR,
+		.pgpolicy      = GROUP_BY_SERIAL,
+		.pgfailback    = FAILBACK_UNDEF,
+		.rr_weight     = RR_WEIGHT_NONE,
+		.no_path_retry = NO_PATH_RETRY_UNDEF,
+		.minio         = DEFAULT_MINIO,
+		.checker_name  = TUR,
+	},
+	{
+		/* IBM S/390 ECKD DASD */
+		.vendor        = "IBM",
+		.product       = "S/390 DASD ECKD",
+		.getuid        = "/sbin/dasdview -j /dev/%n",
+		.getprio       = NULL,
+		.features      = DEFAULT_FEATURES,
+		.hwhandler     = DEFAULT_HWHANDLER,
+		.selector      = DEFAULT_SELECTOR,
+		.pgpolicy      = MULTIBUS,
+		.pgfailback    = FAILBACK_UNDEF,
+		.rr_weight     = RR_WEIGHT_NONE,
+		.no_path_retry = NO_PATH_RETRY_UNDEF,
+		.minio         = DEFAULT_MINIO,
+		.checker_name  = DIRECTIO,
+	},
+	/*
+	 * NETAPP controler family
+	 *
+	 * Maintainer : Igor Feoktistov
+	 * Mail : igorf at netapp.com
+	 */
+	{
+		.vendor        = "NETAPP",
+		.product       = "LUN",
+		.getuid        = DEFAULT_GETUID,
+		.getprio       = "/sbin/mpath_prio_netapp /dev/%n",
+		.features      = "1 queue_if_no_path",
+		.hwhandler     = DEFAULT_HWHANDLER,
+		.selector      = DEFAULT_SELECTOR,
+		.pgpolicy      = GROUP_BY_PRIO,
+		.pgfailback    = FAILBACK_UNDEF,
+		.rr_weight     = RR_WEIGHT_NONE,
+		.no_path_retry = NO_PATH_RETRY_UNDEF,
+		.minio         = DEFAULT_MINIO,
+		.checker_name  = READSECTOR0,
+	},
+	/*
+	 * Pillar Data controler family
+	 *
+	 * Maintainer : Christophe Varoqui
+	 * Mail : christophe.varoqui at free.fr
+	 */
+	{
+		.vendor        = "Pillar",
+		.product       = "Axiom 500",
+		.getuid        = DEFAULT_GETUID,
+		.getprio       = "/sbin/mpath_prio_alua %d",
+		.features      = DEFAULT_FEATURES,
+		.hwhandler     = DEFAULT_HWHANDLER,
+		.selector      = DEFAULT_SELECTOR,
+		.pgpolicy      = GROUP_BY_PRIO,
+		.pgfailback    = FAILBACK_UNDEF,
+		.rr_weight     = RR_WEIGHT_NONE,
+		.no_path_retry = NO_PATH_RETRY_UNDEF,
+		.minio         = DEFAULT_MINIO,
+		.checker_name  = TUR,
+	},
+	/*
+	 * SGI arrays
+	 *
+	 * Maintainer : Christophe Varoqui
+	 * Mail : christophe.varoqui at free.fr
+	 */
+	{
+		.vendor        = "SGI",
+		.product       = "TP9[13]00",
+		.getuid        = DEFAULT_GETUID,
+		.getprio       = NULL,
+		.features      = DEFAULT_FEATURES,
+		.hwhandler     = DEFAULT_HWHANDLER,
+		.selector      = DEFAULT_SELECTOR,
+		.pgpolicy      = MULTIBUS,
+		.pgfailback    = FAILBACK_UNDEF,
+		.rr_weight     = RR_WEIGHT_NONE,
+		.no_path_retry = NO_PATH_RETRY_UNDEF,
+		.minio         = DEFAULT_MINIO,
+		.checker_name  = READSECTOR0,
+	},
+	{
+		.vendor        = "SGI",
+		.product       = "TP9[45]00",
+		.getuid        = DEFAULT_GETUID,
+		.getprio       = "/sbin/mpath_prio_tpc /dev/%n",
+		.features      = DEFAULT_FEATURES,
+		.hwhandler     = DEFAULT_HWHANDLER,
+		.selector      = DEFAULT_SELECTOR,
+		.pgpolicy      = GROUP_BY_PRIO,
+		.pgfailback    = -FAILBACK_IMMEDIATE,
+		.rr_weight     = RR_WEIGHT_NONE,
+		.no_path_retry = NO_PATH_RETRY_UNDEF,
+		.minio         = DEFAULT_MINIO,
+		.checker_name  = TUR,
+	},
+	/*
+	 * STK arrays
+	 *
+	 * Maintainer : Christophe Varoqui
+	 * Mail : christophe.varoqui at free.fr
+	 */
+	{
+		.vendor        = "STK",
+		.product       = "OPENstorage D280",
+		.getuid        = DEFAULT_GETUID,
+		.getprio       = "/sbin/mpath_prio_tpc /dev/%n",
+		.features      = DEFAULT_FEATURES,
+		.hwhandler     = DEFAULT_HWHANDLER,
+		.selector      = DEFAULT_SELECTOR,
+		.pgpolicy      = GROUP_BY_PRIO,
+		.pgfailback    = -FAILBACK_IMMEDIATE,
+		.rr_weight     = RR_WEIGHT_NONE,
+		.no_path_retry = NO_PATH_RETRY_UNDEF,
+		.minio         = DEFAULT_MINIO,
+		.checker_name  = TUR,
+	},
+	/*
+	 * SUN arrays
+	 *
+	 * Maintainer : Christophe Varoqui
+	 * Mail : christophe.varoqui at free.fr
+	 */
+	{
+		.vendor        = "SUN",
+		.product       = "{StorEdge 3510,T4}",
+		.getuid        = DEFAULT_GETUID,
+		.getprio       = NULL,
+		.features      = DEFAULT_FEATURES,
+		.hwhandler     = DEFAULT_HWHANDLER,
+		.selector      = DEFAULT_SELECTOR,
+		.pgpolicy      = MULTIBUS,
+		.pgfailback    = FAILBACK_UNDEF,
+		.rr_weight     = RR_WEIGHT_NONE,
+		.no_path_retry = NO_PATH_RETRY_UNDEF,
+		.minio         = DEFAULT_MINIO,
+		.checker_name  = READSECTOR0,
+	},
+	/*
+	 * EOL
+	 */
+	{
+		.vendor        = NULL,
+		.product       = NULL,
+		.getuid        = NULL,
+		.getprio       = NULL,
+		.features      = NULL,
+		.hwhandler     = NULL,
+		.selector      = NULL,
+		.pgpolicy      = 0,
+		.pgfailback    = 0,
+		.rr_weight     = 0,
+		.no_path_retry = 0,
+		.minio         = 0,
+		.checker_name  = NULL,
+	},
+};
+
 extern int
 setup_default_hwtable (vector hw)
 {
 	int r = 0;
+	struct hwentry * hwe = default_hw;
 
-	r += store_hwe(hw, "3PARdata", "VV", MULTIBUS, DEFAULT_GETUID);
-	r += store_hwe(hw, "COMPAQ", "HSV110 (C)COMPAQ", GROUP_BY_SERIAL, DEFAULT_GETUID);
-	r += store_hwe(hw, "COMPAQ", "MSA1000", GROUP_BY_SERIAL, DEFAULT_GETUID);
-	r += store_hwe(hw, "COMPAQ", "MSA1000 VOLUME", GROUP_BY_SERIAL, DEFAULT_GETUID);
-	r += store_hwe(hw, "DDN", "SAN DataDirector", MULTIBUS, DEFAULT_GETUID);
-	r += store_hwe(hw, "DEC", "HSG80", GROUP_BY_SERIAL, DEFAULT_GETUID);
-	r += store_hwe(hw, "EMC", "SYMMETRIX", MULTIBUS,
-		       "/sbin/scsi_id -g -u -ppre-spc3-83 -s /block/%n");
-	r += store_hwe(hw, "FSC", "CentricStor", GROUP_BY_SERIAL, DEFAULT_GETUID);
-	r += store_hwe(hw, "HITACHI", "DF400", MULTIBUS, DEFAULT_GETUID);
-	r += store_hwe(hw, "HITACHI", "DF500", MULTIBUS, DEFAULT_GETUID);
-	r += store_hwe(hw, "HITACHI", "DF600", MULTIBUS, DEFAULT_GETUID);
-	r += store_hwe(hw, "HP", "HSV110", GROUP_BY_SERIAL, DEFAULT_GETUID);
-	r += store_hwe(hw, "HP", "HSV210", MULTIBUS, DEFAULT_GETUID);
-	r += store_hwe(hw, "HP", "A6189A", MULTIBUS, DEFAULT_GETUID);
-	r += store_hwe(hw, "HP", "OPEN-", MULTIBUS, DEFAULT_GETUID);
-	r += store_hwe(hw, "IBM", "ProFibre 4000R", MULTIBUS, DEFAULT_GETUID);
-	r += store_hwe(hw, "NETAPP", "LUN", MULTIBUS, DEFAULT_GETUID);
-	r += store_hwe(hw, "SGI", "TP9100", MULTIBUS, DEFAULT_GETUID);
-	r += store_hwe(hw, "SGI", "TP9300", MULTIBUS, DEFAULT_GETUID);
-	r += store_hwe(hw, "STK", "OPENstorage D280", GROUP_BY_SERIAL, DEFAULT_GETUID);
-	r += store_hwe(hw, "SUN", "StorEdge 3510", MULTIBUS, DEFAULT_GETUID);
-	r += store_hwe(hw, "SUN", "T4", MULTIBUS, DEFAULT_GETUID);
-
-	r += store_hwe_ext(hw, "DGC", "*", GROUP_BY_PRIO, DEFAULT_GETUID,
-		   "/sbin/mpath_prio_emc /dev/%n", "1 emc",
-		   "1 queue_if_no_path", "emc_clariion", FAILBACK_IMMEDIATE);
-	r += store_hwe_ext(hw, "IBM", "3542", GROUP_BY_SERIAL, DEFAULT_GETUID,
-		   NULL, "0", "0", "tur", FAILBACK_UNDEF);
-	r += store_hwe_ext(hw, "SGI", "TP9400", MULTIBUS, DEFAULT_GETUID,
-		   NULL, "0", "0", "tur", FAILBACK_UNDEF);
-	r += store_hwe_ext(hw, "SGI", "TP9500", FAILOVER, DEFAULT_GETUID,
-		   NULL, "0", "0", "tur", FAILBACK_UNDEF);
-
+	while (hwe->vendor) {
+		hwe->checker = checker_lookup(hwe->checker_name);
+		r += store_hwe(hw, hwe);
+		hwe++;
+	}
 	return r;
 }
-

Modified: multipath-tools/trunk/libmultipath/log.c
==============================================================================
--- multipath-tools/trunk/libmultipath/log.c	(original)
+++ multipath-tools/trunk/libmultipath/log.c	Mon Mar 13 15:16:41 2006
@@ -1,3 +1,8 @@
+/*
+ * Copyright (c) 2005 Christophe Varoqui
+ * Copyright (c) 2005 Benjamin Marzinski, Redhat
+ * Copyright (c) 2005 Jun'ichi Nomura, NEC
+ */
 #include <stdio.h>
 #include <stdlib.h>
 #include <stdarg.h>

Modified: multipath-tools/trunk/libmultipath/log_pthread.c
==============================================================================
--- multipath-tools/trunk/libmultipath/log_pthread.c	(original)
+++ multipath-tools/trunk/libmultipath/log_pthread.c	Mon Mar 13 15:16:41 2006
@@ -1,3 +1,6 @@
+/*
+ * Copyright (c) 2005 Christophe Varoqui
+ */
 #include <stdio.h>
 #include <stdlib.h>
 #include <stdarg.h>

Modified: multipath-tools/trunk/libmultipath/parser.c
==============================================================================
--- multipath-tools/trunk/libmultipath/parser.c	(original)
+++ multipath-tools/trunk/libmultipath/parser.c	Mon Mar 13 15:16:41 2006
@@ -24,9 +24,11 @@
 
 /* local vars */
 static int sublevel = 0;
+vector keywords = NULL;
 
 int
-keyword_alloc(vector keywords, char *string, int (*handler) (vector))
+keyword_alloc(vector keywords, char *string, int (*handler) (vector),
+		int (*print) (char *, int, void *))
 {
 	struct keyword *keyword;
 
@@ -41,6 +43,7 @@
 	}
 	keyword->string = string;
 	keyword->handler = handler;
+	keyword->print = print;
 
 	vector_set_slot(keywords, keyword);
 
@@ -50,7 +53,7 @@
 int
 install_keyword_root(char *string, int (*handler) (vector))
 {
-	return keyword_alloc(keywords, string, handler);
+	return keyword_alloc(keywords, string, handler, NULL);
 }
 
 void
@@ -66,7 +69,8 @@
 }
 
 int
-install_keyword(char *string, int (*handler) (vector))
+install_keyword(char *string, int (*handler) (vector),
+		int (*print) (char *, int, void *))
 {
 	int i = 0;
 	struct keyword *keyword;
@@ -87,7 +91,7 @@
 		return 1;
 
 	/* add new sub keyword */
-	return keyword_alloc(keyword->sub, string, handler);
+	return keyword_alloc(keyword->sub, string, handler, print);
 }
 
 void
@@ -105,6 +109,73 @@
 	vector_free(keywords);
 }
 
+struct keyword *
+find_keyword(vector v, char * name)
+{
+	struct keyword *keyword;
+	int i;
+	int len;
+
+	if (!name || !keywords)
+		return NULL;
+
+	if (!v)
+		v = keywords;
+
+	len = strlen(name);
+
+	for (i = 0; i < VECTOR_SIZE(v); i++) {
+		keyword = VECTOR_SLOT(v, i);
+		if ((strlen(keyword->string) == len) &&
+		    !strcmp(keyword->string, name))
+			return keyword;
+		if (keyword->sub) {
+			keyword = find_keyword(keyword->sub, name);
+			if (keyword)
+				return keyword;
+		}
+	}
+	return NULL;
+}
+
+int
+snprint_keyword(char *buff, int len, char *fmt, struct keyword *kw, void *data)
+{
+	int r;
+	int fwd = 0;
+	char *f = fmt;
+
+	if (!kw || !kw->print)
+		return 0;
+
+	do {
+		if (fwd == len || *f == '\0')
+			break;
+		if (*f != '%') {
+			*(buff + fwd) = *f;
+			fwd++;
+			continue;
+		}
+		f++;
+		switch(*f) {
+		case 'k':
+			fwd += snprintf(buff + fwd, len - fwd, kw->string);
+			break;
+		case 'v':
+			r = kw->print(buff + fwd, len - fwd, data);
+			if (!r) { /* no output if no value */
+				buff = '\0';
+				return 0;
+			}
+			fwd += r;
+			break;
+		}
+		if (fwd > len)
+			fwd = len;
+	} while (*f++);
+	return fwd;
+}
+
 vector
 alloc_strvec(char *string)
 {
@@ -373,10 +444,14 @@
 
 /* Data initialization */
 int
-init_data(char *conf_file, vector (*init_keywords) (void))
+init_data(char *conf_file, void (*init_keywords) (void))
 {
 	int r;
 
+	if (!keywords)
+		keywords = vector_alloc();
+	if (!keywords)
+		return 1;
 	stream = fopen(conf_file, "r");
 	if (!stream) {
 		syslog(LOG_WARNING, "Configuration file open problem");
@@ -394,7 +469,7 @@
 	/* Stream handling */
 	r = process_stream(keywords);
 	fclose(stream);
-	free_keywords(keywords);
+	//free_keywords(keywords);
 
 	return r;
 }

Modified: multipath-tools/trunk/libmultipath/parser.h
==============================================================================
--- multipath-tools/trunk/libmultipath/parser.h	(original)
+++ multipath-tools/trunk/libmultipath/parser.h	Mon Mar 13 15:16:41 2006
@@ -42,24 +42,30 @@
 struct keyword {
 	char *string;
 	int (*handler) (vector);
+	int (*print) (char *, int, void *);
 	vector sub;
 };
 
+/* global var exported */
+FILE *stream;
+
 /* Reloading helpers */
 #define SET_RELOAD      (reload = 1)
 #define UNSET_RELOAD    (reload = 0)
 #define RELOAD_DELAY    5
 
-/* global var exported */
-vector keywords;
-FILE *stream;
+/* iterator helper */
+#define iterate_sub_keywords(k,p,i) \
+	for (i = 0; i < (k)->sub->allocated && ((p) = (k)->sub->slot[i]); i++)
 
 /* Prototypes */
-extern int keyword_alloc(vector keywords, char *string, int (*handler) (vector));
+extern int keyword_alloc(vector keywords, char *string, int (*handler) (vector),
+			 int (*print) (char *, int, void *));
 extern int install_keyword_root(char *string, int (*handler) (vector));
 extern void install_sublevel(void);
 extern void install_sublevel_end(void);
-extern int install_keyword(char *string, int (*handler) (vector));
+extern int install_keyword(char *string, int (*handler) (vector),
+			   int (*print) (char *, int, void *));
 extern void dump_keywords(vector keydump, int level);
 extern void free_keywords(vector keywords);
 extern vector alloc_strvec(char *string);
@@ -68,6 +74,9 @@
 extern int alloc_value_block(vector strvec, void (*alloc_func) (vector));
 extern void *set_value(vector strvec);
 extern int process_stream(vector keywords);
-extern int init_data(char *conf_file, vector (*init_keywords) (void));
+extern int init_data(char *conf_file, void (*init_keywords) (void));
+extern struct keyword * find_keyword(vector v, char * name);
+int snprint_keyword(char *buff, int len, char *fmt, struct keyword *kw,
+		    void *data);
 
 #endif

Modified: multipath-tools/trunk/libmultipath/pgpolicies.c
==============================================================================
--- multipath-tools/trunk/libmultipath/pgpolicies.c	(original)
+++ multipath-tools/trunk/libmultipath/pgpolicies.c	Mon Mar 13 15:16:41 2006
@@ -1,18 +1,18 @@
 /*
- * Here we define the path grouping policies
+ * Copyright (c) 2004, 2005 Christophe Varoqui
  */
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 
+#include <checkers.h>
+
 #include "util.h"
 #include "memory.h"
 #include "vector.h"
 #include "structs.h"
 #include "pgpolicies.h"
 
-#include "../libcheckers/path_state.h"
-
 extern int
 get_pgpolicy_id (char * str)
 {
@@ -31,7 +31,7 @@
 }
 
 extern int
-get_pgpolicy_name (char * buff, int id)
+get_pgpolicy_name (char * buff, int len, int id)
 {
 	char * s;
 
@@ -55,11 +55,7 @@
 		s = "undefined";
 		break;
 	}
-	if(safe_snprintf(buff, POLICY_NAME_SIZE, "%s", s)) {
-		fprintf(stderr, "get_pgpolicy_name: buff too small\n");
-		return 1;
-	}
-	return 0;
+	return snprintf(buff, POLICY_NAME_SIZE, "%s", s);
 }
 
 /*

Modified: multipath-tools/trunk/libmultipath/pgpolicies.h
==============================================================================
--- multipath-tools/trunk/libmultipath/pgpolicies.h	(original)
+++ multipath-tools/trunk/libmultipath/pgpolicies.h	Mon Mar 13 15:16:41 2006
@@ -20,7 +20,7 @@
 };
 
 int get_pgpolicy_id(char *);
-int get_pgpolicy_name (char *, int);
+int get_pgpolicy_name (char *, int, int);
 
 /*
  * policies

Modified: multipath-tools/trunk/libmultipath/print.c
==============================================================================
--- multipath-tools/trunk/libmultipath/print.c	(original)
+++ multipath-tools/trunk/libmultipath/print.c	Mon Mar 13 15:16:41 2006
@@ -1,130 +1,467 @@
+/*
+ * Copyright (c) 2005 Christophe Varoqui
+ */
 #include <stdio.h>
 #include <string.h>
-#include <math.h>
 #include <libdevmapper.h>
+#include <stdarg.h>
+
+#include <checkers.h>
 
 #include "vector.h"
 #include "structs.h"
+#include "structs_vec.h"
 #include "print.h"
 #include "dmparser.h"
+#include "configure.h"
+#include "config.h"
+#include "pgpolicies.h"
+#include "defaults.h"
+#include "parser.h"
 
-#include "../libcheckers/path_state.h"
+#define MAX(x,y) (x > y) ? x : y
+#define TAIL     (line + len - 1 - c)
+#define NOPAD    s = c
+#define PAD(x)   while ((int)(c - s) < (x) && (c < (line + len - 1))) \
+			*c++ = ' '; s = c
+#define PRINT(var, size, format, args...)      \
+	         fwd = snprintf(var, size, format, ##args); \
+		 c += (fwd >= size) ? size : fwd;
 
-#define MAX_FIELD_LEN 64
+/*
+ * information printing helpers
+ */
+static int
+snprint_str (char * buff, size_t len, char * str)
+{
+	return snprintf(buff, len, "%s", str);
+}
 
-#define MAX(x,y) (x > y) ? x : y
+static int
+snprint_int (char * buff, size_t len, int val)
+{
+	return snprintf(buff, len, "%i", val);
+}
+
+static int
+snprint_uint (char * buff, size_t len, unsigned int val)
+{
+	return snprintf(buff, len, "%u", val);
+}
+
+static int
+snprint_size (char * buff, size_t len, unsigned long long size)
+{
+	if (size < (1 << 11))
+		return snprintf(buff, len, "%llu kB", size >> 1);
+	else if (size < (1 << 21))
+		return snprintf(buff, len, "%llu MB", size >> 11);
+	else if (size < (1 << 31))
+		return snprintf(buff, len, "%llu GB", size >> 21);
+	else
+		return snprintf(buff, len, "%llu TB", size >> 31);
+}
+
+static int
+snprint_name (char * buff, size_t len, struct multipath * mpp)
+{
+	if (mpp->alias)
+		return snprintf(buff, len, "%s", mpp->alias);
+	else
+		return snprintf(buff, len, "%s", mpp->wwid);
+}
+
+static int
+snprint_sysfs (char * buff, size_t len, struct multipath * mpp)
+{
+	if (mpp->dmi)
+		return snprintf(buff, len, "dm-%i", mpp->dmi->minor);
+
+	return 0;
+}
+
+static int
+snprint_progress (char * buff, size_t len, int cur, int total)
+{
+	int i = PROGRESS_LEN * cur / total;
+	int j = PROGRESS_LEN - i;
+	char * c = buff;
+	char * end = buff + len;
+	
+	while (i-- > 0) {
+		c += snprintf(c, len, "X");
+		if ((len = (end - c)) <= 1) goto out;
+	}
+
+	while (j-- > 0) {
+		c += snprintf(c, len,  ".");
+		if ((len = (end - c)) <= 1) goto out;
+	}
+
+	c += snprintf(c, len, " %i/%i", cur, total);
+
+out:
+	buff[c - buff + 1] = '\0';
+	return (c - buff + 1);
+}
+	
+static int
+snprint_failback (char * buff, size_t len, struct multipath * mpp)
+{
+	if (mpp->pgfailback == -FAILBACK_IMMEDIATE)
+		return snprintf(buff, len, "immediate");
+
+	if (!mpp->failback_tick)
+		return snprintf(buff, len, "-");
+	else
+		return snprint_progress(buff, len, mpp->failback_tick,
+					mpp->pgfailback);
+}
+
+static int
+snprint_queueing (char * buff, size_t len, struct multipath * mpp)
+{
+	if (mpp->no_path_retry == NO_PATH_RETRY_FAIL)
+		return snprintf(buff, len, "off");
+	else if (mpp->no_path_retry == NO_PATH_RETRY_QUEUE)
+		return snprintf(buff, len, "on");
+	else if (mpp->no_path_retry == NO_PATH_RETRY_UNDEF)
+		return snprintf(buff, len, "-");
+	else if (mpp->no_path_retry > 0) {
+		if (mpp->retry_tick)
+			return snprintf(buff, len, "%i sec",
+					mpp->retry_tick);
+		else
+			return snprintf(buff, len, "%i chk",
+					mpp->no_path_retry);
+	}
+	return 0;
+}
+
+static int
+snprint_nb_paths (char * buff, size_t len, struct multipath * mpp)
+{
+	return snprint_int(buff, len, mpp->nr_active);
+}
+
+static int
+snprint_dm_map_state (char * buff, size_t len, struct multipath * mpp)
+{
+	if (mpp->dmi && mpp->dmi->suspended)
+		return snprintf(buff, len, "suspend");
+	else
+		return snprintf(buff, len, "active");
+}
+
+static int
+snprint_multipath_size (char * buff, size_t len, struct multipath * mpp)
+{
+	return snprint_size(buff, len, mpp->size);
+}
+
+static int
+snprint_features (char * buff, size_t len, struct multipath * mpp)
+{
+	return snprint_str(buff, len, mpp->features);
+}
+
+static int
+snprint_hwhandler (char * buff, size_t len, struct multipath * mpp)
+{
+	return snprint_str(buff, len, mpp->hwhandler);
+}
+
+static int
+snprint_path_faults (char * buff, size_t len, struct multipath * mpp)
+{
+	return snprint_uint(buff, len, mpp->stat_path_failures);
+}
+
+static int
+snprint_switch_grp (char * buff, size_t len, struct multipath * mpp)
+{
+	return snprint_uint(buff, len, mpp->stat_switchgroup);
+}
+
+static int
+snprint_map_loads (char * buff, size_t len, struct multipath * mpp)
+{
+	return snprint_uint(buff, len, mpp->stat_map_loads);
+}
+
+static int
+snprint_total_q_time (char * buff, size_t len, struct multipath * mpp)
+{
+	return snprint_uint(buff, len, mpp->stat_total_queueing_time);
+}
+
+static int
+snprint_q_timeouts (char * buff, size_t len, struct multipath * mpp)
+{
+	return snprint_uint(buff, len, mpp->stat_queueing_timeouts);
+}
+
+static int
+snprint_multipath_uuid (char * buff, size_t len, struct multipath * mpp)
+{
+	return snprint_str(buff, len, mpp->wwid);
+}
+
+static int
+snprint_action (char * buff, size_t len, struct multipath * mpp)
+{
+	switch (mpp->action) {
+	case ACT_RELOAD:
+		return snprint_str(buff, len, ACT_RELOAD_STR);
+	case ACT_CREATE:
+		return snprint_str(buff, len, ACT_CREATE_STR);
+	case ACT_SWITCHPG:
+		return snprint_str(buff, len, ACT_SWITCHPG_STR);
+	default:
+		return 0;
+	}
+}
+
+static int
+snprint_path_uuid (char * buff, size_t len, struct path * pp)
+{
+	return snprint_str(buff, len, pp->wwid);
+}
+
+static int
+snprint_hcil (char * buff, size_t len, struct path * pp)
+{
+	if (pp->sg_id.host_no < 0)
+		return snprintf(buff, len, "#:#:#:#");
+
+	return snprintf(buff, len, "%i:%i:%i:%i",
+			pp->sg_id.host_no,
+			pp->sg_id.channel,
+			pp->sg_id.scsi_id,
+			pp->sg_id.lun);
+}
+
+static int
+snprint_dev (char * buff, size_t len, struct path * pp)
+{
+	if (!strlen(pp->dev))
+		return snprintf(buff, len, "-");
+	else
+		return snprint_str(buff, len, pp->dev);
+}
+
+static int
+snprint_dev_t (char * buff, size_t len, struct path * pp)
+{
+	if (!strlen(pp->dev))
+		return snprintf(buff, len, "#:#");
+	else
+		return snprint_str(buff, len, pp->dev_t);
+}
+
+static int
+snprint_chk_state (char * buff, size_t len, struct path * pp)
+{
+	switch (pp->state) {
+	case PATH_UP:
+		return snprintf(buff, len, "[ready]");
+	case PATH_DOWN:
+		return snprintf(buff, len, "[faulty]");
+	case PATH_SHAKY:
+		return snprintf(buff, len, "[shaky]");
+	case PATH_GHOST:
+		return snprintf(buff, len, "[ghost]");
+	default:
+		return snprintf(buff, len, "[undef]");
+	}
+}
+
+static int
+snprint_dm_path_state (char * buff, size_t len, struct path * pp)
+{
+	switch (pp->dmstate) {
+	case PSTATE_ACTIVE:
+		return snprintf(buff, len, "[active]");
+	case PSTATE_FAILED:
+		return snprintf(buff, len, "[failed]");
+	default:
+		return snprintf(buff, len, "[undef]");
+	}
+}
+
+static int
+snprint_vpr (char * buff, size_t len, struct path * pp)
+{
+	return snprintf(buff, len, "%s/%s/%s",
+		        pp->vendor_id, pp->product_id, pp->rev);
+}
+
+static int
+snprint_next_check (char * buff, size_t len, struct path * pp)
+{
+	if (!pp->mpp)
+		return snprintf(buff, len, "[orphan]");
+
+	return snprint_progress(buff, len, pp->tick, pp->checkint);
+}
+
+static int
+snprint_pri (char * buff, size_t len, struct path * pp)
+{
+	return snprint_int(buff, len, pp->priority);
+}
+
+static int
+snprint_pg_selector (char * buff, size_t len, struct pathgroup * pgp)
+{
+	return snprint_str(buff, len, pgp->selector);
+}
+
+static int
+snprint_pg_pri (char * buff, size_t len, struct pathgroup * pgp)
+{
+	return snprint_int(buff, len, pgp->priority);
+}
+
+static int
+snprint_pg_state (char * buff, size_t len, struct pathgroup * pgp)
+{
+	switch (pgp->status) {
+	case PGSTATE_ENABLED:
+		return snprintf(buff, len, "[enabled]");
+	case PGSTATE_DISABLED:
+		return snprintf(buff, len, "[disabled]");
+	case PGSTATE_ACTIVE:
+		return snprintf(buff, len, "[active]");
+	default:
+		return snprintf(buff, len, "[undef]");
+	}
+}
+
+static int
+snprint_path_size (char * buff, size_t len, struct path * pp)
+{
+	return snprint_size(buff, len, pp->size);
+}
+
+struct multipath_data mpd[] = {
+	{'n', "name",          0, snprint_name},
+	{'w', "uuid",          0, snprint_multipath_uuid},
+	{'d', "sysfs",         0, snprint_sysfs},
+	{'F', "failback",      0, snprint_failback},
+	{'Q', "queueing",      0, snprint_queueing},
+	{'N', "paths",         0, snprint_nb_paths},
+	{'t', "dm-st",         0, snprint_dm_map_state},
+	{'S', "size",          0, snprint_multipath_size},
+	{'f', "features",      0, snprint_features},
+	{'h', "hwhandler",     0, snprint_hwhandler},
+	{'A', "action",        0, snprint_action},
+	{'0', "path_faults",   0, snprint_path_faults},
+	{'1', "switch_grp",    0, snprint_switch_grp},
+	{'2', "map_loads",     0, snprint_map_loads},
+	{'3', "total_q_time",  0, snprint_total_q_time},
+	{'4', "q_timeouts",    0, snprint_q_timeouts},
+	{0, NULL, 0 , NULL}
+};
+
+struct path_data pd[] = {
+	{'w', "uuid",          0, snprint_path_uuid},
+	{'i', "hcil",          0, snprint_hcil},
+	{'d', "dev",           0, snprint_dev},
+	{'D', "dev_t",         0, snprint_dev_t},
+	{'t', "dm_st",         0, snprint_dm_path_state},
+	{'T', "chk_st",        0, snprint_chk_state},
+	{'s', "vend/prod/rev", 0, snprint_vpr},
+	{'C', "next_check",    0, snprint_next_check},
+	{'p', "pri",           0, snprint_pri},
+	{'S', "size",          0, snprint_path_size},
+	{0, NULL, 0 , NULL}
+};
+
+struct pathgroup_data pgd[] = {
+	{'s', "selector",      0, snprint_pg_selector},
+	{'p', "pri",           0, snprint_pg_pri},
+	{'t', "dm_st",         0, snprint_pg_state},
+};
 
 void
-get_path_layout (struct path_layout * pl, vector pathvec)
+get_path_layout (vector pathvec)
 {
-	int i;
+	int i, j;
 	char buff[MAX_FIELD_LEN];
 	struct path * pp;
 
-	int uuid_len;
-	int hbtl_len;
-	int dev_len;
-	int dev_t_len;
-	int prio_len;
-
-	/* reset max col lengths */
-	pl->uuid_len = 0;
-	pl->hbtl_len = 0;
-	pl->dev_len = 0;
-	pl->dev_t_len = 0;
-	pl->prio_len = 0;
-
-	vector_foreach_slot (pathvec, pp, i) {
-		uuid_len = strlen(pp->wwid);
-		hbtl_len = snprintf(buff, MAX_FIELD_LEN, "%i:%i:%i:%i",
-					pp->sg_id.host_no,
-					pp->sg_id.channel,
-					pp->sg_id.scsi_id,
-					pp->sg_id.lun);
-		dev_len = strlen(pp->dev);
-		dev_t_len = strlen(pp->dev_t);
-		prio_len = 1 + (int)log10(pp->priority);
-
-		pl->uuid_len = MAX(uuid_len, pl->uuid_len);
-		pl->hbtl_len = MAX(hbtl_len, pl->hbtl_len);
-		pl->dev_len = MAX(dev_len, pl->dev_len);
-		pl->dev_t_len = MAX(dev_t_len, pl->dev_t_len);
-		pl->prio_len = MAX(prio_len, pl->prio_len);
+	for (j = 0; pd[j].header; j++) {
+		pd[j].width = strlen(pd[j].header);
+
+		vector_foreach_slot (pathvec, pp, i) {
+			pd[j].snprint(buff, MAX_FIELD_LEN, pp);
+			pd[j].width = MAX(pd[j].width, strlen(buff));
+		}
 	}
-	return;
 }
 
 void
-get_map_layout (struct map_layout * ml, vector mpvec)
+get_multipath_layout (vector mpvec)
 {
-	int i;
+	int i, j;
 	char buff[MAX_FIELD_LEN];
 	struct multipath * mpp;
 
-	int mapname_len;
-	int mapdev_len;
-	int failback_progress_len;
-	int queueing_progress_len;
-	int nr_active_len;
-
-	/* reset max col lengths */
-	ml->mapname_len = 0;
-	ml->mapdev_len = 0;
-	ml->failback_progress_len = 0;
-	ml->queueing_progress_len = 0;
-	ml->nr_active_len = 0;
-
-	vector_foreach_slot (mpvec, mpp, i) {
-		mapname_len = (mpp->alias) ?
-				strlen(mpp->alias) : strlen(mpp->wwid);
-		if (mpp->dmi) mapdev_len = snprintf(buff, MAX_FIELD_LEN,
-			       	      "dm-%i", mpp->dmi->minor);
-		failback_progress_len = 4 + PROGRESS_LEN +
-					(int)log10(mpp->failback_tick) +
-					(int)log10(mpp->pgfailback);
-		queueing_progress_len = 5 + (int)log10(mpp->retry_tick);
-		nr_active_len = (int)log10(mpp->nr_active);
-
-		ml->mapname_len = MAX(mapname_len, ml->mapname_len);
-		ml->mapdev_len = MAX(mapdev_len, ml->mapdev_len);
-		ml->failback_progress_len = MAX(failback_progress_len,
-						ml->failback_progress_len);
-		ml->queueing_progress_len = MAX(queueing_progress_len,
-						ml->queueing_progress_len);
-		ml->nr_active_len = MAX(nr_active_len, ml->nr_active_len);
+	for (j = 0; mpd[j].header; j++) {
+		mpd[j].width = strlen(mpd[j].header);
+
+		vector_foreach_slot (mpvec, mpp, i) {
+			mpd[j].snprint(buff, MAX_FIELD_LEN, mpp);
+			mpd[j].width = MAX(mpd[j].width, strlen(buff));
+		}
 	}
-	return;
 }
 
-#define TAIL   (line + len - 1 - c)
-#define PAD(x) while ((int)(c - s) < (x) && (c < (line + len - 1))) \
-			*c++ = ' '; s = c
-#define NOPAD  s = c
+static struct multipath_data *
+mpd_lookup(char wildcard)
+{
+	int i;
 
-#define PRINT(var, size, format, args...)      \
-	        fwd = snprintf(var, size, format, ##args); \
-		c += (fwd >= size) ? size : fwd;
+	for (i = 0; mpd[i].header; i++)
+		if (mpd[i].wildcard == wildcard)
+			return &mpd[i];
 
-#define PRINT_PROGRESS(cur, total)			\
-		int i = PROGRESS_LEN * cur / total;	\
-		int j = PROGRESS_LEN - i;		\
-							\
-		while (i-- > 0) {			\
-			PRINT(c, TAIL, "X");		\
-		}					\
-		while (j-- > 0) {			\
-			PRINT(c, TAIL, ".");		\
-		}					\
-		PRINT(c, TAIL, " %i/%i", cur, total)
+	return NULL;
+}
+
+static struct path_data *
+pd_lookup(char wildcard)
+{
+	int i;
+
+	for (i = 0; pd[i].header; i++)
+		if (pd[i].wildcard == wildcard)
+			return &pd[i];
+
+	return NULL;
+}
+
+static struct pathgroup_data *
+pgd_lookup(char wildcard)
+{
+	int i;
+
+	for (i = 0; pgd[i].header; i++)
+		if (pgd[i].wildcard == wildcard)
+			return &pgd[i];
+
+	return NULL;
+}
 
 int
-snprint_map_header (char * line, int len, char * format,
-	            struct map_layout * ml)
+snprint_multipath_header (char * line, int len, char * format)
 {
 	char * c = line;   /* line cursor */
 	char * s = line;   /* for padding */
 	char * f = format; /* format string cursor */
 	int fwd;
+	struct multipath_data * data;
 
 	do {
 		if (!TAIL)
@@ -136,41 +473,12 @@
 			continue;
 		}
 		f++;
-		switch (*f) {
-		case 'w':	
-			PRINT(c, TAIL, "name");
-			ml->mapname_len = MAX(ml->mapname_len, 4);
-			PAD(ml->mapname_len);
-			break;
-		case 'd':
-			PRINT(c, TAIL, "sysfs");
-			ml->mapdev_len = MAX(ml->mapdev_len, 5);
-			PAD(ml->mapdev_len);
-			break;
-		case 'F':
-			PRINT(c, TAIL, "failback");
-			ml->failback_progress_len =
-				MAX(ml->failback_progress_len, 8);
-			PAD(ml->failback_progress_len);
-			break;
-		case 'Q':
-			PRINT(c, TAIL, "queueing");
-			ml->queueing_progress_len =
-				MAX(ml->queueing_progress_len, 8);
-			PAD(ml->queueing_progress_len);
-			break;
-		case 'n':
-			PRINT(c, TAIL, "paths");
-			ml->nr_active_len = MAX(ml->nr_active_len, 5);
-			PAD(ml->nr_active_len);
-			break;
-		case 't':
-			PRINT(c, TAIL, "dm-st");
-			PAD(7);
-			break;
-		default:
-			break;
-		}
+		
+		if (!(data = mpd_lookup(*f)))
+			break; /* unknown wildcard */
+		
+		PRINT(c, TAIL, data->header);
+		PAD(data->width);
 	} while (*f++);
 
 	line[c - line - 1] = '\n';
@@ -180,13 +488,15 @@
 }
 
 int
-snprint_map (char * line, int len, char * format,
-	     struct multipath * mpp, struct map_layout * ml)
+snprint_multipath (char * line, int len, char * format,
+	     struct multipath * mpp)
 {
 	char * c = line;   /* line cursor */
 	char * s = line;   /* for padding */
 	char * f = format; /* format string cursor */
 	int fwd;
+	struct multipath_data * data;
+	char buff[MAX_FIELD_LEN];
 
 	do {
 		if (!TAIL)
@@ -198,63 +508,13 @@
 			continue;
 		}
 		f++;
-		switch (*f) {
-		case 'w':	
-			if (mpp->alias) {
-				PRINT(c, TAIL, "%s", mpp->alias);
-			} else {
-				PRINT(c, TAIL, "%s", mpp->wwid);
-			}
-			PAD(ml->mapname_len);
-			break;
-		case 'd':
-			if (mpp->dmi) {
-				PRINT(c, TAIL, "dm-%i", mpp->dmi->minor);
-			}
-			PAD(ml->mapdev_len);
-			break;
-		case 'F':
-			if (!mpp->failback_tick) {
-				PRINT(c, TAIL, "-");
-			} else {
-				PRINT_PROGRESS(mpp->failback_tick,
-					       mpp->pgfailback);
-			}
-			PAD(ml->failback_progress_len);
-			break;
-		case 'Q':
-			if (mpp->no_path_retry == NO_PATH_RETRY_FAIL) {
-				PRINT(c, TAIL, "off");
-			} else if (mpp->no_path_retry == NO_PATH_RETRY_QUEUE) {
-				PRINT(c, TAIL, "on");
-			} else if (mpp->no_path_retry == NO_PATH_RETRY_UNDEF) {
-				PRINT(c, TAIL, "-");
-			} else if (mpp->no_path_retry > 0) {
-				if (mpp->retry_tick) {
-					PRINT(c, TAIL, "%i sec",
-					      mpp->retry_tick);
-				} else {
-					PRINT(c, TAIL, "%i chk",
-					      mpp->no_path_retry);
-				}
-			}
-			PAD(ml->queueing_progress_len);
-			break;
-		case 'n':
-			PRINT(c, TAIL, "%i", mpp->nr_active);
-			PAD(ml->nr_active_len);
-			break;
-		case 't':
-			if (mpp->dmi && mpp->dmi->suspended) {
-				PRINT(c, TAIL, "suspend");
-			} else {
-				PRINT(c, TAIL, "active");
-			}
-			PAD(7);
+		
+		if (!(data = mpd_lookup(*f)))
 			break;
-		default:
-			break;
-		}
+		
+		data->snprint(buff, MAX_FIELD_LEN, mpp);
+		PRINT(c, TAIL, buff);
+		PAD(data->width);
 	} while (*f++);
 
 	line[c - line - 1] = '\n';
@@ -264,13 +524,13 @@
 }
 
 int
-snprint_path_header (char * line, int len, char * format,
-		     struct path_layout * pl)
+snprint_path_header (char * line, int len, char * format)
 {
 	char * c = line;   /* line cursor */
 	char * s = line;   /* for padding */
 	char * f = format; /* format string cursor */
 	int fwd;
+	struct path_data * data;
 
 	do {
 		if (!TAIL)
@@ -282,49 +542,12 @@
 			continue;
 		}
 		f++;
-		switch (*f) {
-		case 'w':
-			PRINT(c, TAIL, "uuid");
-			PAD(pl->uuid_len);
-			break;
-		case 'i':
-			PRINT(c, TAIL, "hcil");
-			PAD(pl->hbtl_len);
-			break;
-		case 'd':
-			PRINT(c, TAIL, "dev");
-			pl->dev_len = MAX(pl->dev_len, 3);
-			PAD(pl->dev_len);
-			break;
-		case 'D':
-			PRINT(c, TAIL, "dev_t");
-			pl->dev_t_len = MAX(pl->dev_t_len, 5);
-			PAD(pl->dev_t_len);
-			break;
-		case 'T':
-			PRINT(c, TAIL, "chk-st");
-			PAD(8);
-			break;
-		case 't':
-			PRINT(c, TAIL, "dm-st");
-			PAD(8);
-			break;
-		case 's':
-			PRINT(c, TAIL, "vendor/product/rev");
-			NOPAD;
-			break;
-		case 'C':
-			PRINT(c, TAIL, "next-check");
-			NOPAD;
-			break;
-		case 'p':
-			PRINT(c, TAIL, "pri");
-			pl->prio_len = MAX(pl->prio_len, 3);
-			PAD(pl->prio_len);
-			break;
-		default:
-			break;
-		}
+		
+		if (!(data = pd_lookup(*f)))
+			break; /* unknown wildcard */
+		
+		PRINT(c, TAIL, data->header);
+		PAD(data->width);
 	} while (*f++);
 
 	line[c - line - 1] = '\n';
@@ -334,13 +557,15 @@
 }
 
 int
-snprint_path (char * line, int len, char * format, struct path * pp,
-	    struct path_layout * pl)
+snprint_path (char * line, int len, char * format,
+	     struct path * pp)
 {
 	char * c = line;   /* line cursor */
 	char * s = line;   /* for padding */
 	char * f = format; /* format string cursor */
 	int fwd;
+	struct path_data * data;
+	char buff[MAX_FIELD_LEN];
 
 	do {
 		if (!TAIL)
@@ -352,93 +577,49 @@
 			continue;
 		}
 		f++;
-		switch (*f) {
-		case 'w':	
-			PRINT(c, TAIL, "%s", pp->wwid);
-			PAD(pl->uuid_len);
-			break;
-		case 'i':
-			if (pp->sg_id.host_no < 0) {
-				PRINT(c, TAIL, "#:#:#:#");
-			} else {
-				PRINT(c, TAIL, "%i:%i:%i:%i",
-					pp->sg_id.host_no,
-					pp->sg_id.channel,
-					pp->sg_id.scsi_id,
-					pp->sg_id.lun);
-			}
-			PAD(pl->hbtl_len);
+		
+		if (!(data = pd_lookup(*f)))
 			break;
-		case 'd':
-			if (!strlen(pp->dev)) {
-				PRINT(c, TAIL, "-");
-			} else {
-				PRINT(c, TAIL, "%s", pp->dev);
-			}
-			PAD(pl->dev_len);
-			break;
-		case 'D':
-			PRINT(c, TAIL, "%s", pp->dev_t);
-			PAD(pl->dev_t_len);
-			break;
-		case 'T':
-			switch (pp->state) {
-			case PATH_UP:
-				PRINT(c, TAIL, "[ready]");
-				break;
-			case PATH_DOWN:
-				PRINT(c, TAIL, "[faulty]");
-				break;
-			case PATH_SHAKY:
-				PRINT(c, TAIL, "[shaky]");
-				break;
-			case PATH_GHOST:
-				PRINT(c, TAIL, "[ghost]");
-				break;
-			default:
-				PRINT(c, TAIL, "[undef]");
-				break;
-			}
-			PAD(8);
-			break;
-		case 't':
-			switch (pp->dmstate) {
-			case PSTATE_ACTIVE:
-				PRINT(c, TAIL, "[active]");
-				break;
-			case PSTATE_FAILED:
-				PRINT(c, TAIL, "[failed]");
-				break;
-			default:
-				PRINT(c, TAIL, "[undef]");
-				break;
-			}
-			PAD(8);
-			break;
-		case 's':
-			PRINT(c, TAIL, "%s/%s/%s",
-				      pp->vendor_id, pp->product_id, pp->rev);
-			NOPAD;
+		
+		data->snprint(buff, MAX_FIELD_LEN, pp);
+		PRINT(c, TAIL, buff);
+		PAD(data->width);
+	} while (*f++);
+
+	line[c - line - 1] = '\n';
+	line[c - line] = '\0';
+
+	return (c - line);
+}
+
+int
+snprint_pathgroup (char * line, int len, char * format,
+		   struct pathgroup * pgp)
+{
+	char * c = line;   /* line cursor */
+	char * s = line;   /* for padding */
+	char * f = format; /* format string cursor */
+	int fwd;
+	struct pathgroup_data * data;
+	char buff[MAX_FIELD_LEN];
+
+	do {
+		if (!TAIL)
 			break;
-		case 'C':
-			if (!pp->mpp) {
-				PRINT(c, TAIL, "[orphan]");
-			} else {
-				PRINT_PROGRESS(pp->tick, pp->checkint);
-			}
+
+		if (*f != '%') {
+			*c++ = *f;
 			NOPAD;
-			break;
-		case 'p':
-			if (pp->priority) {
-				PRINT(c, TAIL, "%i", pp->priority);
-			} else {
-				PRINT(c, TAIL, "#");
-			}
-			PAD(pl->prio_len);
-			break;
-		default:
-			break;
+			continue;
 		}
+		f++;
+		
+		if (!(data = pgd_lookup(*f)))
+			break;
+		
+		data->snprint(buff, MAX_FIELD_LEN, pgp);
+		PRINT(c, TAIL, buff);
+		PAD(data->width);
 	} while (*f++);
 
 	line[c - line - 1] = '\n';
@@ -447,3 +628,347 @@
 	return (c - line);
 }
 
+extern void
+print_multipath_topology (struct multipath * mpp, int verbosity)
+{
+	char buff[MAX_LINE_LEN * MAX_LINES];
+
+	snprint_multipath_topology(&buff[0], MAX_LINE_LEN * MAX_LINES,
+				   mpp, verbosity);
+	printf("%s", buff);
+}
+
+extern int
+snprint_multipath_topology (char * buff, int len, struct multipath * mpp,
+			    int verbosity)
+{
+	int j, i, fwd = 0;
+	struct path * pp = NULL;
+	struct pathgroup * pgp = NULL;
+	char style[64];
+	char * c = style;
+
+	if (verbosity <= 0)
+		return fwd;
+
+	if (verbosity == 1)
+		return snprint_multipath(buff, len, "%n", mpp);
+
+	if (verbosity > 1 &&
+	    mpp->action != ACT_NOTHING &&
+	    mpp->action != ACT_UNDEF)
+			c += sprintf(c, "%%A: ");
+
+	c += sprintf(c, "%%n");
+	
+	if (strncmp(mpp->alias, mpp->wwid, WWID_SIZE))
+		c += sprintf(c, " (%%w)");
+
+	fwd += snprint_multipath(buff + fwd, len - fwd, style, mpp);
+	if (fwd > len)
+		return len;
+	fwd += snprint_multipath(buff + fwd, len - fwd,
+				 "[size=%S][features=%f][hwhandler=%h]", mpp);
+	if (fwd > len)
+		return len;
+
+	if (!mpp->pg)
+		return fwd;
+
+	vector_foreach_slot (mpp->pg, pgp, j) {
+		pgp->selector = mpp->selector; /* hack */
+		fwd += snprint_pathgroup(buff + fwd, len - fwd,
+					 PRINT_PG_INDENT, pgp);
+		if (fwd > len)
+			return len;
+
+		vector_foreach_slot (pgp->paths, pp, i) {
+			fwd += snprint_path(buff + fwd, len - fwd,
+					    PRINT_PATH_INDENT, pp);
+			if (fwd > len)
+				return len;
+		}
+	}
+	return fwd;
+}
+
+static int
+snprint_hwentry (char * buff, int len, struct hwentry * hwe)
+{
+	int i;
+	int fwd = 0;
+	struct keyword * kw;
+	struct keyword * rootkw;
+
+	rootkw = find_keyword(NULL, "devices");
+
+	if (!rootkw || !rootkw->sub)
+		return 0;
+
+	rootkw = find_keyword(rootkw->sub, "device");
+
+	if (!rootkw)
+		return 0;
+
+	fwd += snprintf(buff + fwd, len - fwd, "\tdevice {\n");
+	if (fwd > len)
+		return len;
+	iterate_sub_keywords(rootkw, kw, i) {
+		fwd += snprint_keyword(buff + fwd, len - fwd, "\t\t%k %v\n",
+				kw, hwe);
+		if (fwd > len)
+			return len;
+	}
+	fwd += snprintf(buff + fwd, len - fwd, "\t}\n");
+	if (fwd > len)
+		return len;
+	return fwd;
+}
+
+extern int
+snprint_hwtable (char * buff, int len, vector hwtable)
+{
+	int fwd = 0;
+	int i;
+	struct hwentry * hwe;
+	struct keyword * rootkw;
+
+	rootkw = find_keyword(NULL, "devices");
+	if (!rootkw)
+		return 0;
+
+	fwd += snprintf(buff + fwd, len - fwd, "devices {\n");
+	if (fwd > len)
+		return len;
+	vector_foreach_slot (hwtable, hwe, i) {
+		fwd += snprint_hwentry(buff + fwd, len - fwd, hwe);
+		if (fwd > len)
+			return len;
+	}
+	fwd += snprintf(buff + fwd, len - fwd, "}\n");
+	if (fwd > len)
+		return len;
+	return fwd;
+}
+
+static int
+snprint_mpentry (char * buff, int len, struct mpentry * mpe)
+{
+	int i;
+	int fwd = 0;
+	struct keyword * kw;
+	struct keyword * rootkw;
+
+	rootkw = find_keyword(NULL, "multipath");
+	if (!rootkw)
+		return 0;
+
+	fwd += snprintf(buff + fwd, len - fwd, "\tmultipath {\n");
+	if (fwd > len)
+		return len;
+	iterate_sub_keywords(rootkw, kw, i) {
+		fwd += snprint_keyword(buff + fwd, len - fwd, "\t\t%k %v\n",
+				kw, mpe);
+		if (fwd > len)
+			return len;
+	}
+	fwd += snprintf(buff + fwd, len - fwd, "\t}\n");
+	if (fwd > len)
+		return len;
+	return fwd;
+}
+
+extern int
+snprint_mptable (char * buff, int len, vector mptable)
+{
+	int fwd = 0;
+	int i;
+	struct mpentry * mpe;
+	struct keyword * rootkw;
+
+	rootkw = find_keyword(NULL, "multipaths");
+	if (!rootkw)
+		return 0;
+
+	fwd += snprintf(buff + fwd, len - fwd, "multipaths {\n");
+	if (fwd > len)
+		return len;
+	vector_foreach_slot (mptable, mpe, i) {
+		fwd += snprint_mpentry(buff + fwd, len - fwd, mpe);
+		if (fwd > len)
+			return len;
+	}
+	fwd += snprintf(buff + fwd, len - fwd, "}\n");
+	if (fwd > len)
+		return len;
+	return fwd;
+}
+
+extern int
+snprint_defaults (char * buff, int len)
+{
+	int fwd = 0;
+	int i;
+	struct keyword *rootkw;
+	struct keyword *kw;
+
+	rootkw = find_keyword(NULL, "defaults");
+	if (!rootkw)
+		return 0;
+
+	fwd += snprintf(buff + fwd, len - fwd, "defaults {\n");
+	if (fwd > len)
+		return len;
+
+	iterate_sub_keywords(rootkw, kw, i) {
+		fwd += snprint_keyword(buff + fwd, len - fwd, "\t%k %v\n",
+				kw, NULL);
+		if (fwd > len)
+			return len;
+	}
+	fwd += snprintf(buff + fwd, len - fwd, "}\n");
+	if (fwd > len)
+		return len;
+	return fwd;
+	
+}
+
+extern int
+snprint_blacklist (char * buff, int len)
+{
+	int i;
+	struct blentry * ble;
+	struct blentry_device * bled;
+	int fwd = 0;
+	struct keyword *rootkw;
+	struct keyword *kw;
+
+	rootkw = find_keyword(NULL, "blacklist");
+	if (!rootkw)
+		return 0;
+
+	fwd += snprintf(buff + fwd, len - fwd, "blacklist {\n");
+	if (fwd > len)
+		return len;
+
+	vector_foreach_slot (conf->blist_devnode, ble, i) {
+		kw = find_keyword(rootkw->sub, "devnode");
+		if (!kw)
+			return 0;
+		fwd += snprint_keyword(buff + fwd, len - fwd, "\t%k %v\n",
+				       kw, ble);
+		if (fwd > len)
+			return len;
+	}
+	vector_foreach_slot (conf->blist_wwid, ble, i) {
+		kw = find_keyword(rootkw->sub, "wwid");
+		if (!kw)
+			return 0;
+		fwd += snprint_keyword(buff + fwd, len - fwd, "\t%k %v\n",
+				       kw, ble);
+		if (fwd > len)
+			return len;
+	}
+	rootkw = find_keyword(rootkw->sub, "device");
+	if (!rootkw)
+		return 0;
+
+	vector_foreach_slot (conf->blist_device, bled, i) {
+		fwd += snprintf(buff + fwd, len - fwd, "\tdevice {\n");
+		if (fwd > len)
+			return len;
+		kw = find_keyword(rootkw->sub, "vendor");
+		if (!kw)
+			return 0;
+		fwd += snprint_keyword(buff + fwd, len - fwd, "\t\t%k %v\n",
+				       kw, bled);
+		if (fwd > len)
+			return len;
+		kw = find_keyword(rootkw->sub, "product");
+		if (!kw)
+			return 0;
+		fwd += snprint_keyword(buff + fwd, len - fwd, "\t\t%k %v\n",
+				       kw, bled);
+		if (fwd > len)
+			return len;
+		fwd += snprintf(buff + fwd, len - fwd, "\t}\n");
+		if (fwd > len)
+			return len;
+	}
+
+	fwd += snprintf(buff + fwd, len - fwd, "}\n");
+	if (fwd > len)
+		return len;
+	return fwd;
+	
+}
+
+extern int
+snprint_config (char * buff, int len)
+{
+	return 0;
+}
+
+/*
+ * stdout printing helpers
+ */
+extern void
+print_path (struct path * pp, char * style)
+{
+	char line[MAX_LINE_LEN];
+
+	snprint_path(&line[0], MAX_LINE_LEN, style, pp);
+	printf("%s", line);
+}
+
+extern void
+print_multipath (struct multipath * mpp, char * style)
+{
+	char line[MAX_LINE_LEN];
+
+	snprint_multipath(&line[0], MAX_LINE_LEN, style, mpp);
+	printf("%s", line);
+}
+
+extern void
+print_pathgroup (struct pathgroup * pgp, char * style)
+{
+	char line[MAX_LINE_LEN];
+
+	snprint_pathgroup(&line[0], MAX_LINE_LEN, style, pgp);
+	printf("%s", line);
+}
+
+extern void
+print_map (struct multipath * mpp)
+{
+	if (mpp->size && mpp->params)
+		printf("0 %llu %s %s\n",
+			 mpp->size, DEFAULT_TARGET, mpp->params);
+	return;
+}
+
+extern void
+print_all_paths (vector pathvec, int banner)
+{
+	int i;
+	struct path * pp;
+	char line[MAX_LINE_LEN];
+
+	if (!VECTOR_SIZE(pathvec)) {
+		if (banner)
+			fprintf(stdout, "===== no paths =====\n");
+		return;
+	}
+	
+	if (banner)
+		fprintf(stdout, "===== paths list =====\n");
+
+	get_path_layout(pathvec);
+	snprint_path_header(line, MAX_LINE_LEN, PRINT_PATH_LONG);
+	fprintf(stdout, "%s", line);
+
+	vector_foreach_slot (pathvec, pp, i)
+		print_path(pp, PRINT_PATH_LONG);
+}
+

Modified: multipath-tools/trunk/libmultipath/print.h
==============================================================================
--- multipath-tools/trunk/libmultipath/print.h	(original)
+++ multipath-tools/trunk/libmultipath/print.h	Mon Mar 13 15:16:41 2006
@@ -1,53 +1,55 @@
-/*
- * path format magics :
- * 
- * %w : multipath uid
- * %i : scsi tuple
- * %d : device name
- * %D : device major:minor
- * %t : device mapper path status
- * %T : checker path status
- * %s : scsi strings
- * %p : priority
- * 
- * map format magics :
- * 
- * %w : multipath uid
- * %d : DM device name
- * %F : failback countdown
- * %C : checker countdown
- * %Q : queueing policy changer countdown (no_path_retry)
- * %n : number of active paths
- * %t : device mapper map status
- */
 #define PRINT_PATH_LONG      "%w %i %d %D %p %t%T %s"
 #define PRINT_PATH_INDENT    " \\_ %i %d %D %t%T"
 #define PRINT_PATH_CHECKER   "%i %d %D %p %t%T %C"
-#define PRINT_MAP_FAILBACK   "%w %d %F %Q %n %t"
+#define PRINT_MAP_STATUS     "%n %F %Q %N %t"
+#define PRINT_MAP_STATS      "%n %0 %1 %2 %3 %4"
+#define PRINT_MAP_NAMES      "%n %d %w"
+#define PRINT_PG_INDENT      "\\_ %s [prio=%p]%t"
 
-#define MAX_LINE_LEN 80
-#define PROGRESS_LEN 10
+#define MAX_LINE_LEN  80
+#define MAX_LINES     64
+#define MAX_FIELD_LEN 64
+#define PROGRESS_LEN  10
 
-struct path_layout {
-	int uuid_len;
-	int hbtl_len;
-	int dev_len;
-	int dev_t_len;
-	int prio_len;
+struct path_data {
+	char wildcard;
+	char * header;
+	int width;
+	int (*snprint)(char * buff, size_t len, struct path * pp);
 };
 
-struct map_layout {
-	int mapname_len;
-	int mapdev_len;
-	int failback_progress_len;
-	int queueing_progress_len;
-	int nr_active_len;
+struct multipath_data {
+	char wildcard;
+	char * header;
+	int width;
+	int (*snprint)(char * buff, size_t len, struct multipath * mpp);
 };
 
+struct pathgroup_data {
+	char wildcard;
+	char * header;
+	int width;
+	int (*snprint)(char * buff, size_t len, struct pathgroup * pgp);
+};
+
+void get_path_layout (vector pathvec);
+void get_multipath_layout (vector mpvec);
+int snprint_path_header (char *, int, char *);
+int snprint_multipath_header (char *, int, char *);
+int snprint_path (char *, int, char *, struct path *);
+int snprint_multipath (char *, int, char *, struct multipath *);
+int snprint_multipath_topology (char *, int, struct multipath * mpp,
+				int verbosity);
+int snprint_defaults (char *, int);
+int snprint_blacklist (char *, int);
+int snprint_hwtable (char *, int, vector);
+int snprint_mptable (char *, int, vector);
+
+void print_multipath_topology (struct multipath * mpp, int verbosity);
+void print_path (struct path * pp, char * style);
+void print_multipath (struct multipath * mpp, char * style);
+void print_pathgroup (struct pathgroup * pgp, char * style);
+void print_map (struct multipath * mpp);
+void print_all_paths (vector pathvec, int banner);
+void print_hwtable (vector hwtable);
 
-void get_path_layout (struct path_layout * pl, vector pathvec);
-void get_map_layout (struct map_layout * pl, vector mpvec);
-int snprint_path_header (char *, int, char *, struct path_layout *);
-int snprint_map_header (char *, int, char *, struct map_layout *);
-int snprint_path (char *, int, char *, struct path *, struct path_layout *);
-int snprint_map (char *, int, char *,struct multipath *, struct map_layout *);

Modified: multipath-tools/trunk/libmultipath/propsel.c
==============================================================================
--- multipath-tools/trunk/libmultipath/propsel.c	(original)
+++ multipath-tools/trunk/libmultipath/propsel.c	Mon Mar 13 15:16:41 2006
@@ -1,13 +1,29 @@
+/*
+ * Copyright (c) 2004, 2005 Christophe Varoqui
+ * Copyright (c) 2005 Benjamin Marzinski, Redhat
+ * Copyright (c) 2005 Kiyoshi Ueda, NEC
+ */
 #include <stdio.h>
 
+#include <checkers.h>
+
+#include "memory.h"
 #include "vector.h"
 #include "structs.h"
 #include "config.h"
 #include "debug.h"
 #include "pgpolicies.h"
 #include "alias.h"
+#include "defaults.h"
 
-#include "../libcheckers/checkers.h"
+pgpolicyfn *pgpolicies[] = {
+	NULL,
+	one_path_per_group,
+	one_group,
+	group_by_serial,
+	group_by_prio,
+	group_by_node_name
+};
 
 /*
  * selectors :
@@ -19,25 +35,25 @@
 {
 	if (mp->mpe && mp->mpe->rr_weight) {
 		mp->rr_weight = mp->mpe->rr_weight;
-		condlog(3, "rr_weight = %i (LUN setting)",
-			mp->rr_weight);
+		condlog(3, "%s: rr_weight = %i (LUN setting)",
+			mp->alias, mp->rr_weight);
 		return 0;
 	}
 	if (mp->hwe && mp->hwe->rr_weight) {
 		mp->rr_weight = mp->hwe->rr_weight;
-		condlog(3, "rr_weight = %i (controler setting)",
-			mp->rr_weight);
+		condlog(3, "%s: rr_weight = %i (controler setting)",
+			mp->alias, mp->rr_weight);
 		return 0;
 	}
 	if (conf->rr_weight) {
 		mp->rr_weight = conf->rr_weight;
-		condlog(3, "rr_weight = %i (config file default)",
-			mp->rr_weight);
+		condlog(3, "%s: rr_weight = %i (config file default)",
+			mp->alias, mp->rr_weight);
 		return 0;
 	}
 	mp->rr_weight = RR_WEIGHT_NONE;
-	condlog(3, "rr_weight = %i (internal default)",
-		mp->rr_weight);
+	condlog(3, "%s: rr_weight = %i (internal default)",
+		mp->alias, mp->rr_weight);
 	return 0;
 }
 
@@ -46,66 +62,74 @@
 {
 	if (mp->mpe && mp->mpe->pgfailback != FAILBACK_UNDEF) {
 		mp->pgfailback = mp->mpe->pgfailback;
-		condlog(3, "pgfailback = %i (LUN setting)", mp->pgfailback);
+		condlog(3, "%s: pgfailback = %i (LUN setting)",
+			mp->alias, mp->pgfailback);
 		return 0;
 	}
 	if (mp->hwe && mp->hwe->pgfailback != FAILBACK_UNDEF) {
 		mp->pgfailback = mp->hwe->pgfailback;
-		condlog(3, "pgfailback = %i (controler setting)",
-			mp->pgfailback);
+		condlog(3, "%s: pgfailback = %i (controler setting)",
+			mp->alias, mp->pgfailback);
 		return 0;
 	}
 	if (conf->pgfailback != FAILBACK_UNDEF) {
 		mp->pgfailback = conf->pgfailback;
-		condlog(3, "pgfailback = %i (config file default)",
-			mp->pgfailback);
+		condlog(3, "%s: pgfailback = %i (config file default)",
+			mp->alias, mp->pgfailback);
 		return 0;
 	}
-	mp->pgfailback = -FAILBACK_MANUAL;
-	condlog(3, "pgfailover = %i (internal default)", mp->pgfailback);
+	mp->pgfailback = DEFAULT_FAILBACK;
+	condlog(3, "%s: pgfailover = %i (internal default)",
+		mp->alias, mp->pgfailback);
 	return 0;
 }
 
 extern int
 select_pgpolicy (struct multipath * mp)
 {
-	struct path * pp;
 	char pgpolicy_name[POLICY_NAME_SIZE];
 
-	pp = VECTOR_SLOT(mp->paths, 0);
-
 	if (conf->pgpolicy_flag > 0) {
 		mp->pgpolicy = conf->pgpolicy_flag;
-		if (get_pgpolicy_name(pgpolicy_name, mp->pgpolicy))
-			return 1;
-		condlog(3, "pgpolicy = %s (cmd line flag)", pgpolicy_name);
+		mp->pgpolicyfn = pgpolicies[mp->pgpolicy];
+		get_pgpolicy_name(pgpolicy_name, POLICY_NAME_SIZE,
+				  mp->pgpolicy);
+		condlog(3, "%s: pgpolicy = %s (cmd line flag)",
+			mp->alias, pgpolicy_name);
 		return 0;
 	}
 	if (mp->mpe && mp->mpe->pgpolicy > 0) {
 		mp->pgpolicy = mp->mpe->pgpolicy;
-		if (get_pgpolicy_name(pgpolicy_name, mp->pgpolicy))
-			return 1;
-		condlog(3, "pgpolicy = %s (LUN setting)", pgpolicy_name);
+		mp->pgpolicyfn = pgpolicies[mp->pgpolicy];
+		get_pgpolicy_name(pgpolicy_name, POLICY_NAME_SIZE,
+				  mp->pgpolicy);
+		condlog(3, "%s: pgpolicy = %s (LUN setting)",
+			mp->alias, pgpolicy_name);
 		return 0;
 	}
 	if (mp->hwe && mp->hwe->pgpolicy > 0) {
 		mp->pgpolicy = mp->hwe->pgpolicy;
-		if (get_pgpolicy_name(pgpolicy_name, mp->pgpolicy))
-			return 1;
-		condlog(3, "pgpolicy = %s (controler setting)", pgpolicy_name);
-		return 0;
-	}
-	if (conf->default_pgpolicy > 0) {
-		mp->pgpolicy = conf->default_pgpolicy;
-		if (get_pgpolicy_name(pgpolicy_name, mp->pgpolicy))
-			return 1;
-		condlog(3, "pgpolicy = %s (config file default)", pgpolicy_name);
-		return 0;
-	}
-	mp->pgpolicy = FAILOVER;
-	if (get_pgpolicy_name(pgpolicy_name, mp->pgpolicy))
-		return 1;
-	condlog(3, "pgpolicy = %s (internal default)", pgpolicy_name);
+		mp->pgpolicyfn = pgpolicies[mp->pgpolicy];
+		get_pgpolicy_name(pgpolicy_name, POLICY_NAME_SIZE,
+				  mp->pgpolicy);
+		condlog(3, "%s: pgpolicy = %s (controler setting)",
+			mp->alias, pgpolicy_name);
+		return 0;
+	}
+	if (conf->pgpolicy > 0) {
+		mp->pgpolicy = conf->pgpolicy;
+		mp->pgpolicyfn = pgpolicies[mp->pgpolicy];
+		get_pgpolicy_name(pgpolicy_name, POLICY_NAME_SIZE,
+				  mp->pgpolicy);
+		condlog(3, "%s: pgpolicy = %s (config file default)",
+			mp->alias, pgpolicy_name);
+		return 0;
+	}
+	mp->pgpolicy = DEFAULT_PGPOLICY;
+	mp->pgpolicyfn = pgpolicies[mp->pgpolicy];
+	get_pgpolicy_name(pgpolicy_name, POLICY_NAME_SIZE, mp->pgpolicy);
+	condlog(3, "%s: pgpolicy = %s (internal default)",
+		mp->alias, pgpolicy_name);
 	return 0;
 }
 
@@ -114,16 +138,19 @@
 {
 	if (mp->mpe && mp->mpe->selector) {
 		mp->selector = mp->mpe->selector;
-		condlog(3, "selector = %s (LUN setting)", mp->selector);
+		condlog(3, "%s: selector = %s (LUN setting)",
+			mp->alias, mp->selector);
 		return 0;
 	}
 	if (mp->hwe && mp->hwe->selector) {
 		mp->selector = mp->hwe->selector;
-		condlog(3, "selector = %s (controler setting)", mp->selector);
+		condlog(3, "%s: selector = %s (controler setting)",
+			mp->alias, mp->selector);
 		return 0;
 	}
 	mp->selector = conf->selector;
-	condlog(3, "selector = %s (internal default)", mp->selector);
+	condlog(3, "%s: selector = %s (internal default)",
+		mp->alias, mp->selector);
 	return 0;
 }
 
@@ -149,11 +176,13 @@
 {
 	if (mp->hwe && mp->hwe->features) {
 		mp->features = mp->hwe->features;
-		condlog(3, "features = %s (controler setting)", mp->features);
+		condlog(3, "%s: features = %s (controler setting)",
+			mp->alias, mp->features);
 		return 0;
 	}
 	mp->features = conf->features;
-	condlog(3, "features = %s (internal default)", mp->features);
+	condlog(3, "%s: features = %s (internal default)",
+		mp->alias, mp->features);
 	return 0;
 }
 
@@ -162,28 +191,36 @@
 {
 	if (mp->hwe && mp->hwe->hwhandler) {
 		mp->hwhandler = mp->hwe->hwhandler;
-		condlog(3, "hwhandler = %s (controler setting)", mp->hwhandler);
+		condlog(3, "%s: hwhandler = %s (controler setting)",
+			mp->alias, mp->hwhandler);
 		return 0;
 	}
-	mp->hwhandler = conf->default_hwhandler;
-	condlog(3, "hwhandler = %s (internal default)", mp->hwhandler);
+	mp->hwhandler = conf->hwhandler;
+	condlog(3, "%s: hwhandler = %s (internal default)",
+		mp->alias, mp->hwhandler);
 	return 0;
 }
 
 extern int
-select_checkfn(struct path *pp)
+select_checker(struct path *pp)
 {
-	char checker_name[CHECKER_NAME_SIZE];
+	struct checker * c = &pp->checker;
 
-	if (pp->hwe && pp->hwe->checker_index > 0) {
-		get_checker_name(checker_name, pp->hwe->checker_index);
-		condlog(3, "path checker = %s (controler setting)", checker_name);
-		pp->checkfn = get_checker_addr(pp->hwe->checker_index);
+	if (pp->hwe && pp->hwe->checker) {
+		checker_get(c, pp->hwe->checker);
+		condlog(3, "%s: path checker = %s (controler setting)",
+			pp->dev, checker_name(c));
+		return 0;
+	}
+	if (conf->checker) {
+		checker_get(c, conf->checker);
+		condlog(3, "%s: path checker = %s (config file default)",
+			pp->dev, checker_name(c));
 		return 0;
 	}
-	pp->checkfn = get_checker_addr(conf->default_checker_index);
-	get_checker_name(checker_name, conf->default_checker_index);
-	condlog(3, "path checker = %s (internal default)", checker_name);
+	checker_get(c, checker_default());
+	condlog(3, "%s: path checker = %s (internal default)",
+		pp->dev, checker_name(c));
 	return 0;
 }
 
@@ -192,11 +229,19 @@
 {
 	if (pp->hwe && pp->hwe->getuid) {
 		pp->getuid = pp->hwe->getuid;
-		condlog(3, "getuid = %s (controler setting)", pp->getuid);
+		condlog(3, "%s: getuid = %s (controler setting)",
+			pp->dev, pp->getuid);
 		return 0;
 	}
-	pp->getuid = conf->default_getuid;
-	condlog(3, "getuid = %s (internal default)", pp->getuid);
+	if (conf->getuid) {
+		pp->getuid = conf->getuid;
+		condlog(3, "%s: getuid = %s (config file default)",
+			pp->dev, pp->getuid);
+		return 0;
+	}
+	pp->getuid = STRDUP(DEFAULT_GETUID);
+	condlog(3, "%s: getuid = %s (internal default)",
+		pp->dev, pp->getuid);
 	return 0;
 }
 
@@ -205,11 +250,18 @@
 {
 	if (pp->hwe && pp->hwe->getprio) {
 		pp->getprio = pp->hwe->getprio;
-		condlog(3, "getprio = %s (controler setting)", pp->getprio);
+		condlog(3, "%s: getprio = %s (controler setting)",
+			pp->dev, pp->getprio);
 		return 0;
 	}
-	pp->getprio = conf->default_getprio;
-	condlog(3, "getprio = %s (internal default)", pp->getprio);
+	if (conf->getprio) {
+		pp->getprio = conf->getprio;
+		condlog(3, "%s: getprio = %s (config file default)",
+			pp->dev, pp->getprio);
+		return 0;
+	}
+	pp->getprio = DEFAULT_GETPRIO;
+	condlog(3, "%s: getprio = NULL (internal default)", pp->dev);
 	return 0;
 }
 
@@ -218,23 +270,52 @@
 {
 	if (mp->mpe && mp->mpe->no_path_retry != NO_PATH_RETRY_UNDEF) {
 		mp->no_path_retry = mp->mpe->no_path_retry;
-		condlog(3, "no_path_retry = %i (multipath setting)",
-			mp->no_path_retry);
+		condlog(3, "%s: no_path_retry = %i (multipath setting)",
+			mp->alias, mp->no_path_retry);
 		return 0;
 	}
 	if (mp->hwe && mp->hwe->no_path_retry != NO_PATH_RETRY_UNDEF) {
 		mp->no_path_retry = mp->hwe->no_path_retry;
-		condlog(3, "no_path_retry = %i (controler setting)",
-			mp->no_path_retry);
+		condlog(3, "%s: no_path_retry = %i (controler setting)",
+			mp->alias, mp->no_path_retry);
 		return 0;
 	}
 	if (conf->no_path_retry != NO_PATH_RETRY_UNDEF) {
 		mp->no_path_retry = conf->no_path_retry;
-		condlog(3, "no_path_retry = %i (config file default)",
-			mp->no_path_retry);
+		condlog(3, "%s: no_path_retry = %i (config file default)",
+			mp->alias, mp->no_path_retry);
 		return 0;
 	}
 	mp->no_path_retry = NO_PATH_RETRY_UNDEF;
-	condlog(3, "no_path_retry = NONE (internal default)");
+	condlog(3, "%s: no_path_retry = NONE (internal default)",
+		mp->alias);
+	return 0;
+}
+
+extern int
+select_minio (struct multipath * mp)
+{
+	if (mp->mpe && mp->mpe->minio) {
+		mp->minio = mp->mpe->minio;
+		condlog(3, "%s: minio = %i (LUN setting)",
+			mp->alias, mp->minio);
+		return 0;
+	}
+	if (mp->hwe && mp->hwe->minio) {
+		mp->minio = mp->hwe->minio;
+		condlog(3, "%s: minio = %i (controler setting)",
+			mp->alias, mp->minio);
+		return 0;
+	}
+	if (conf->minio) {
+		mp->minio = conf->minio;
+		condlog(3, "%s: minio = %i (config file default)",
+			mp->alias, mp->minio);
+		return 0;
+	}
+	mp->minio = DEFAULT_MINIO;
+	condlog(3, "%s: minio = %i (internal default)",
+		mp->alias, mp->minio);
 	return 0;
 }
+

Modified: multipath-tools/trunk/libmultipath/propsel.h
==============================================================================
--- multipath-tools/trunk/libmultipath/propsel.h	(original)
+++ multipath-tools/trunk/libmultipath/propsel.h	Mon Mar 13 15:16:41 2006
@@ -5,7 +5,8 @@
 int select_alias (struct multipath * mp);
 int select_features (struct multipath * mp);
 int select_hwhandler (struct multipath * mp);
-int select_checkfn(struct path *pp);
+int select_checker(struct path *pp);
 int select_getuid (struct path * pp);
 int select_getprio (struct path * pp);
 int select_no_path_retry(struct multipath *mp);
+int select_minio(struct multipath *mp);

Modified: multipath-tools/trunk/libmultipath/structs.c
==============================================================================
--- multipath-tools/trunk/libmultipath/structs.c	(original)
+++ multipath-tools/trunk/libmultipath/structs.c	Mon Mar 13 15:16:41 2006
@@ -1,13 +1,21 @@
+/*
+ * Copyright (c) 2004, 2005 Christophe Varoqui
+ * Copyright (c) 2004 Stefan Bader, IBM
+ */
 #include <stdio.h>
 #include <unistd.h>
 #include <libdevmapper.h>
 
+#include <checkers.h>
+
 #include "memory.h"
 #include "vector.h"
 #include "util.h"
 #include "structs.h"
 #include "config.h"
 #include "debug.h"
+#include "structs_vec.h"
+#include "blacklist.h"
 
 struct path *
 alloc_path (void)
@@ -32,8 +40,8 @@
 	if (!pp)
 		return;
 
-	if (pp->checker_context)
-		free(pp->checker_context);
+	if (checker_selected(&pp->checker))
+		checker_put(&pp->checker);
 
 	if (pp->fd >= 0)
 		close(pp->fd);
@@ -113,8 +121,8 @@
 	return mpp;
 }
 
-void
-free_multipath (struct multipath * mpp, int free_paths)
+extern void
+free_multipath_attributes (struct multipath * mpp)
 {
 	if (!mpp)
 		return;
@@ -122,27 +130,52 @@
 	if (mpp->selector &&
 	    mpp->selector != conf->selector &&
 	    (!mpp->mpe || (mpp->mpe && mpp->selector != mpp->mpe->selector)) &&
-	    (!mpp->hwe || (mpp->hwe && mpp->selector != mpp->hwe->selector)))
+	    (!mpp->hwe || (mpp->hwe && mpp->selector != mpp->hwe->selector))) {
 		FREE(mpp->selector);
-
-	if (mpp->alias &&
-	    (!mpp->mpe || (mpp->mpe && mpp->alias != mpp->mpe->alias)) &&
-	    (mpp->wwid && mpp->alias != mpp->wwid))
-		FREE(mpp->alias);
+		mpp->selector = NULL;
+	}
 
 	if (mpp->features &&
 	    mpp->features != conf->features &&
-	    (!mpp->hwe || (mpp->hwe && mpp->features != mpp->hwe->features)))
+	    (!mpp->hwe || (mpp->hwe && mpp->features != mpp->hwe->features))) {
 		FREE(mpp->features);
+		mpp->features = NULL;
+	}
 
 	if (mpp->hwhandler &&
-	    mpp->hwhandler != conf->default_hwhandler &&
-	    (!mpp->hwe || (mpp->hwe && mpp->hwhandler != mpp->hwe->hwhandler)))
+	    mpp->hwhandler != conf->hwhandler &&
+	    (!mpp->hwe || (mpp->hwe && mpp->hwhandler != mpp->hwe->hwhandler))) {
 		FREE(mpp->hwhandler);
+		mpp->hwhandler = NULL;
+	}
+}
+
+void
+free_multipath (struct multipath * mpp, int free_paths)
+{
+	if (!mpp)
+		return;
+
+	free_multipath_attributes(mpp);
+
+	if (mpp->alias &&
+	    (!mpp->mpe || (mpp->mpe && mpp->alias != mpp->mpe->alias)) &&
+	    (mpp->wwid && mpp->alias != mpp->wwid)) {
+		FREE(mpp->alias);
+		mpp->alias = NULL;
+	}
 
 	if (mpp->dmi)
 		FREE(mpp->dmi);
 	
+#if DAEMON
+	/*
+	 * better own vecs->lock here
+	 */
+	if (mpp->waiter)
+		((struct event_thread *)mpp->waiter)->mpp = NULL;
+#endif
+
 	free_pathvec(mpp->paths, free_paths);
 	free_pgvec(mpp->pg, free_paths);
 	FREE(mpp);
@@ -204,28 +237,34 @@
 }
 
 struct multipath *
-find_mp_by_minor (vector mp, int minor)
+find_mp_by_minor (vector mpvec, int minor)
 {
 	int i;
 	struct multipath * mpp;
 	
-	if (!mpp->dmi)
+	if (!mpvec)
 		return NULL;
 
-	vector_foreach_slot (mp, mpp, i)
+	vector_foreach_slot (mpvec, mpp, i) {
+		if (!mpp->dmi)
+			continue;
+
 		if (mpp->dmi->minor == minor)
 			return mpp;
-
+	}
 	return NULL;
 }
 
 struct multipath *
-find_mp_by_wwid (vector mp, char * wwid)
+find_mp_by_wwid (vector mpvec, char * wwid)
 {
 	int i;
 	struct multipath * mpp;
 	
-	vector_foreach_slot (mp, mpp, i)
+	if (!mpvec)
+		return NULL;
+
+	vector_foreach_slot (mpvec, mpp, i)
 		if (!strncmp(mpp->wwid, wwid, WWID_SIZE))
 			return mpp;
 
@@ -233,18 +272,21 @@
 }
 
 struct multipath *
-find_mp_by_alias (vector mp, char * alias)
+find_mp_by_alias (vector mpvec, char * alias)
 {
 	int i;
 	int len;
 	struct multipath * mpp;
 	
+	if (!mpvec)
+		return NULL;
+
 	len = strlen(alias);
 
 	if (!len)
 		return NULL;
 	
-	vector_foreach_slot (mp, mpp, i) {
+	vector_foreach_slot (mpvec, mpp, i) {
 		if (strlen(mpp->alias) == len &&
 		    !strncmp(mpp->alias, alias, len))
 			return mpp;
@@ -252,17 +294,31 @@
 	return NULL;
 }
 
+struct multipath *
+find_mp_by_str (vector mpvec, char * str)
+{
+	int minor;
+
+	if (sscanf(str, "dm-%d", &minor) == 1)
+		return find_mp_by_minor(mpvec, minor);
+	else
+		return find_mp_by_alias(mpvec, str);
+}
+
 struct path *
 find_path_by_dev (vector pathvec, char * dev)
 {
 	int i;
 	struct path * pp;
+
+	if (!pathvec)
+		return NULL;
 	
 	vector_foreach_slot (pathvec, pp, i)
 		if (!strcmp_chomp(pp->dev, dev))
 			return pp;
 
-	condlog(3, "path %s not found in pathvec\n", dev);
+	condlog(3, "%s: not found in pathvec", dev);
 	return NULL;
 }
 
@@ -272,11 +328,40 @@
 	int i;
 	struct path * pp;
 
+	if (!pathvec)
+		return NULL;
+
 	vector_foreach_slot (pathvec, pp, i)
 		if (!strcmp_chomp(pp->dev_t, dev_t))
 			return pp;
 
-	condlog(3, "path %s not found in pathvec\n", dev_t);
+	condlog(3, "%s: not found in pathvec", dev_t);
 	return NULL;
 }
 
+extern int
+pathcountgr (struct pathgroup * pgp, int state)
+{
+	struct path *pp;
+	int count = 0;
+	int i;
+
+	vector_foreach_slot (pgp->paths, pp, i)
+		if ((pp->state == state) || (state < 0))
+			count++;
+
+	return count;
+}
+
+extern int
+pathcount (struct multipath * mpp, int state)
+{
+	struct pathgroup *pgp;
+	int count = 0;
+	int i;
+
+	vector_foreach_slot (mpp->pg, pgp, i)
+		count += pathcountgr(pgp, state);
+
+	return count;
+}

Modified: multipath-tools/trunk/libmultipath/structs.h
==============================================================================
--- multipath-tools/trunk/libmultipath/structs.h	(original)
+++ multipath-tools/trunk/libmultipath/structs.h	Mon Mar 13 15:16:41 2006
@@ -38,7 +38,8 @@
 enum sysfs_buses {
 	SYSFS_BUS_UNDEF,
 	SYSFS_BUS_SCSI,
-	SYSFS_BUS_IDE
+	SYSFS_BUS_IDE,
+	SYSFS_BUS_CCW,
 };
 
 enum pathstates {
@@ -99,8 +100,8 @@
 	int pgindex;
 	char * getuid;
 	char * getprio;
-	int (*checkfn) (int, char *, void **);
-	void * checker_context;
+	int getprio_selected;
+	struct checker checker;
 	struct multipath * mpp;
 	int fd;
 	
@@ -108,9 +109,13 @@
 	struct hwentry * hwe;
 };
 
+typedef int (pgpolicyfn) (struct multipath *);
+
 struct multipath {
 	char wwid[WWID_SIZE];
+	char alias_old[WWID_SIZE];
 	int pgpolicy;
+	pgpolicyfn *pgpolicyfn;
 	int nextpg;
 	int bestpg;
 	int queuedio;
@@ -121,6 +126,7 @@
 	int nr_active;     /* current available(= not known as failed) paths */
 	int no_path_retry; /* number of retries after all paths are down */
 	int retry_tick;    /* remaining times for retries */
+	int minio;
 	unsigned long long size;
 	vector paths;
 	vector pg;
@@ -138,6 +144,13 @@
 
 	/* daemon store a data blob for DM event waiter threads */
 	void * waiter;
+
+	/* stats */
+	unsigned int stat_switchgroup;
+	unsigned int stat_path_failures;
+	unsigned int stat_map_loads;
+	unsigned int stat_total_queueing_time;
+	unsigned int stat_queueing_timeouts;
 };
 
 struct pathgroup {
@@ -145,6 +158,7 @@
 	int status;
 	int priority;
 	vector paths;
+	char * selector;
 };
 
 struct path * alloc_path (void);
@@ -155,6 +169,7 @@
 void free_pathgroup (struct pathgroup * pgp, int free_paths);
 void free_pgvec (vector pgvec, int free_paths);
 void free_multipath (struct multipath *, int free_paths);
+void free_multipath_attributes (struct multipath *);
 void drop_multipath (vector mpvec, char * wwid, int free_paths);
 void free_multipathvec (vector mpvec, int free_paths);
 
@@ -163,11 +178,15 @@
 
 struct multipath * find_mp_by_alias (vector mp, char * alias);
 struct multipath * find_mp_by_wwid (vector mp, char * wwid);
+struct multipath * find_mp_by_str (vector mp, char * wwid);
 struct multipath * find_mp_by_minor (vector mp, int minor);
 	
 struct path * find_path_by_devt (vector pathvec, char * devt);
 struct path * find_path_by_dev (vector pathvec, char * dev);
 
+int pathcountgr (struct pathgroup *, int);
+int pathcount (struct multipath *, int);
+
 char sysfs_path[FILE_NAME_SIZE];
 
 #endif

Added: multipath-tools/trunk/libmultipath/structs_vec.c
==============================================================================
--- (empty file)
+++ multipath-tools/trunk/libmultipath/structs_vec.c	Mon Mar 13 15:16:41 2006
@@ -0,0 +1,384 @@
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <checkers.h>
+
+#include "vector.h"
+#include "defaults.h"
+#include "debug.h"
+#include "structs.h"
+#include "structs_vec.h"
+#include "devmapper.h"
+#include "dmparser.h"
+#include "config.h"
+#include "propsel.h"
+#include "discovery.h"
+
+
+/*
+ * creates or updates mpp->paths reading mpp->pg
+ */
+extern int
+update_mpp_paths(struct multipath * mpp, vector pathvec)
+{
+	struct pathgroup * pgp;
+	struct path * pp;
+	int i,j;
+
+	if (!mpp->pg)
+		return 0;
+
+	if (!mpp->paths &&
+	    !(mpp->paths = vector_alloc()))
+		return 1;
+
+	vector_foreach_slot (mpp->pg, pgp, i) {
+		vector_foreach_slot (pgp->paths, pp, j) {
+			if (!find_path_by_devt(mpp->paths, pp->dev_t) &&
+			    (find_path_by_devt(pathvec, pp->dev_t)) &&
+			    store_path(mpp->paths, pp))
+				return 1;
+		}
+	}
+	return 0;
+}
+
+extern int
+adopt_paths (vector pathvec, struct multipath * mpp)
+{
+	int i;
+	struct path * pp;
+
+	if (!mpp)
+		return 0;
+
+	if (update_mpp_paths(mpp, pathvec))
+		return 1;
+
+	vector_foreach_slot (pathvec, pp, i) {
+		if (!strncmp(mpp->wwid, pp->wwid, WWID_SIZE)) {
+			condlog(3, "%s ownership set to %s",
+				pp->dev_t, mpp->alias);
+			pp->mpp = mpp;
+			
+			if (!mpp->paths && !(mpp->paths = vector_alloc()))
+				return 1;
+
+			if (!find_path_by_dev(mpp->paths, pp->dev) &&
+			    store_path(mpp->paths, pp))
+					return 1;
+			pathinfo(pp, conf->hwtable, DI_PRIO | DI_CHECKER);
+		}
+	}
+	return 0;
+}
+
+extern void
+orphan_path (struct path * pp)
+{
+	pp->mpp = NULL;
+	pp->dmstate = PSTATE_UNDEF;
+	pp->getuid = NULL;
+	pp->getprio = NULL;
+	pp->getprio_selected = 0;
+	checker_put(&pp->checker);
+	if (pp->fd >= 0)
+		close(pp->fd);
+	pp->fd = -1;
+}
+
+extern void
+orphan_paths (vector pathvec, struct multipath * mpp)
+{
+	int i;
+	struct path * pp;
+
+	vector_foreach_slot (pathvec, pp, i) {
+		if (pp->mpp == mpp) {
+			condlog(4, "%s is orphaned", pp->dev_t);
+			orphan_path(pp);
+		}
+	}
+}
+
+static void
+set_multipath_wwid (struct multipath * mpp)
+{
+	if (mpp->wwid)
+		return;
+
+	dm_get_uuid(mpp->alias, mpp->wwid);
+}
+
+extern void
+remove_map (struct multipath * mpp, struct vectors * vecs,
+	    stop_waiter_thread_func *stop_waiter, int purge_vec)
+{
+	int i;
+
+	/*
+	 * stop the DM event waiter thread
+	 */
+	if (stop_waiter)
+		stop_waiter(mpp, vecs);
+
+	/*
+	 * clear references to this map
+	 */
+	orphan_paths(vecs->pathvec, mpp);
+
+	if (purge_vec &&
+	    (i = find_slot(vecs->mpvec, (void *)mpp)) != -1)
+		vector_del_slot(vecs->mpvec, i);
+
+	/*
+	 * final free
+	 */
+	free_multipath(mpp, KEEP_PATHS);
+}
+
+extern void
+remove_maps (struct vectors * vecs,
+	     stop_waiter_thread_func *stop_waiter)
+{
+	int i;
+	struct multipath * mpp;
+
+	vector_foreach_slot (vecs->mpvec, mpp, i) {
+		remove_map(mpp, vecs, stop_waiter, 1);
+		i--;
+	}
+
+	vector_free(vecs->mpvec);
+	vecs->mpvec = NULL;
+}
+
+static struct hwentry *
+extract_hwe_from_path(struct multipath * mpp)
+{
+	struct path * pp;
+	struct pathgroup * pgp;
+
+	pgp = VECTOR_SLOT(mpp->pg, 0);
+	pp = VECTOR_SLOT(pgp->paths, 0);
+
+	return pp->hwe;
+}
+
+static int
+update_multipath_table (struct multipath *mpp, vector pathvec)
+{
+	if (!mpp)
+		return 1;
+
+	if (dm_get_map(mpp->alias, &mpp->size, mpp->params))
+		return 1;
+
+	if (disassemble_map(pathvec, mpp->params, mpp))
+		return 1;
+
+	return 0;
+}
+
+static int
+update_multipath_status (struct multipath *mpp)
+{
+	if (!mpp)
+		return 1;
+
+	if(dm_get_status(mpp->alias, mpp->status))
+		return 1;
+
+	if (disassemble_status(mpp->status, mpp))
+		return 1;
+
+	return 0;
+}
+
+extern int
+update_multipath_strings (struct multipath *mpp, vector pathvec)
+{
+	free_multipath_attributes(mpp);
+	free_pgvec(mpp->pg, KEEP_PATHS);
+	mpp->pg = NULL;
+
+	if (update_multipath_table(mpp, pathvec))
+		return 1;
+
+	if (update_multipath_status(mpp))
+		return 1;
+
+	return 0;
+}
+
+extern void
+set_no_path_retry(struct multipath *mpp)
+{
+	mpp->retry_tick = 0;
+	mpp->nr_active = pathcount(mpp, PATH_UP) + pathcount(mpp, PATH_GHOST);
+	select_no_path_retry(mpp);
+
+	switch (mpp->no_path_retry) {
+	case NO_PATH_RETRY_UNDEF:
+		break;
+	case NO_PATH_RETRY_FAIL:
+		dm_queue_if_no_path(mpp->alias, 0);
+		break;
+	case NO_PATH_RETRY_QUEUE:
+		dm_queue_if_no_path(mpp->alias, 1);
+		break;
+	default:
+		dm_queue_if_no_path(mpp->alias, 1);
+		if (mpp->nr_active == 0) {
+			/* Enter retry mode */
+			mpp->retry_tick = mpp->no_path_retry * conf->checkint;
+			condlog(1, "%s: Entering recovery mode: max_retries=%d",
+				mpp->alias, mpp->no_path_retry);
+		}
+		break;
+	}
+}
+
+extern int
+setup_multipath (struct vectors * vecs, struct multipath * mpp)
+{
+retry:
+	if (dm_get_info(mpp->alias, &mpp->dmi))
+		goto out;
+
+	set_multipath_wwid(mpp);
+	mpp->mpe = find_mpe(mpp->wwid);
+	condlog(3, "%s: discover", mpp->alias);
+
+	if (update_multipath_strings(mpp, vecs->pathvec)) {
+		char new_alias[WWID_SIZE];
+
+		/*
+	 	 * detect an external rename of the multipath device
+		 */
+		if (dm_get_name(mpp->wwid, DEFAULT_TARGET, new_alias)) {
+			condlog(3, "%s multipath mapped device name has "
+				"changed from %s to %s", mpp->wwid,
+				mpp->alias, new_alias);
+			strcpy(mpp->alias, new_alias);
+#if DAEMON
+			if (mpp->waiter) 
+				strncpy(((struct event_thread *)mpp->waiter)->mapname,
+					new_alias, WWID_SIZE);
+#endif
+			goto retry;
+		}
+		goto out;
+	}
+
+	//adopt_paths(vecs->pathvec, mpp);
+	mpp->hwe = extract_hwe_from_path(mpp);
+	select_rr_weight(mpp);
+	select_pgfailback(mpp);
+	set_no_path_retry(mpp);
+
+	return 0;
+out:
+	condlog(0, "%s: failed to setup multipath", mpp->alias);
+	remove_map(mpp, vecs, NULL, 1);
+	return 1;
+}
+
+extern struct multipath *
+add_map_without_path (struct vectors * vecs,
+		      int minor, char * alias,
+		      start_waiter_thread_func *start_waiter)
+{
+	struct multipath * mpp = alloc_multipath();
+
+	if (!mpp)
+		return NULL;
+
+	mpp->alias = alias;
+
+	if (setup_multipath(vecs, mpp))
+		return NULL; /* mpp freed in setup_multipath */
+
+	if (adopt_paths(vecs->pathvec, mpp))
+		goto out;
+	
+	if (!vector_alloc_slot(vecs->mpvec))
+		goto out;
+
+	vector_set_slot(vecs->mpvec, mpp);
+
+	if (start_waiter(mpp, vecs))
+		goto out;
+
+	return mpp;
+out:
+	remove_map(mpp, vecs, NULL, 1);
+	return NULL;
+}
+
+extern struct multipath *
+add_map_with_path (struct vectors * vecs,
+		   struct path * pp, int add_vec)
+{
+	struct multipath * mpp;
+
+	if (!(mpp = alloc_multipath()))
+		return NULL;
+
+	mpp->mpe = find_mpe(pp->wwid);
+	mpp->hwe = pp->hwe;
+
+	strcpy(mpp->wwid, pp->wwid);
+	select_alias(mpp);
+	mpp->size = pp->size;
+
+	if (adopt_paths(vecs->pathvec, mpp))
+		goto out;
+
+	if (add_vec) {
+		if (!vector_alloc_slot(vecs->mpvec))
+			goto out;
+
+		vector_set_slot(vecs->mpvec, mpp);
+	}
+
+	return mpp;
+
+out:
+	remove_map(mpp, vecs, NULL, add_vec);
+	return NULL;
+}
+
+extern int
+verify_paths(struct multipath * mpp, struct vectors * vecs, vector rpvec)
+{
+	struct path * pp;
+	int count = 0;
+	int i, j;
+
+	vector_foreach_slot (mpp->paths, pp, i) {
+		/*
+		 * see if path is in sysfs
+		 */
+		if (!pp->dev || sysfs_get_dev(sysfs_path,
+				  pp->dev, pp->dev_t, BLK_DEV_SIZE)) {
+			condlog(0, "%s: failed to access path %s", mpp->alias,
+				pp->dev ? pp->dev : pp->dev_t);
+			count++;
+			vector_del_slot(mpp->paths, i);
+			i--;
+
+			if (rpvec)
+				store_path(rpvec, pp);
+			else {
+				if ((j = find_slot(vecs->pathvec,
+						   (void *)pp)) != -1)
+					vector_del_slot(vecs->pathvec, j);
+				free_path(pp);
+			}
+		}
+	}
+	return count;
+}
+

Added: multipath-tools/trunk/libmultipath/structs_vec.h
==============================================================================
--- (empty file)
+++ multipath-tools/trunk/libmultipath/structs_vec.h	Mon Mar 13 15:16:41 2006
@@ -0,0 +1,48 @@
+#ifndef _STRUCTS_VEC_H
+#define _STRUCTS_VEC_H
+
+struct vectors {
+#if DAEMON
+	pthread_mutex_t *lock;
+#endif
+	vector pathvec;
+	vector mpvec;
+};
+
+#if DAEMON
+struct event_thread {
+	struct dm_task *dmt;
+	pthread_t thread;
+	int event_nr;
+	char mapname[WWID_SIZE];
+	struct vectors *vecs;
+	struct multipath *mpp;
+};
+#endif
+
+typedef void (stop_waiter_thread_func) (struct multipath *, struct vectors *);
+typedef int (start_waiter_thread_func) (struct multipath *, struct vectors *);
+
+void set_no_path_retry(struct multipath *mpp);
+
+int adopt_paths (vector pathvec, struct multipath * mpp);
+void orphan_paths (vector pathvec, struct multipath * mpp);
+void orphan_path (struct path * pp);
+
+int verify_paths(struct multipath * mpp, struct vectors * vecs, vector rpvec);
+int update_mpp_paths(struct multipath * mpp, vector pathvec);
+int setup_multipath (struct vectors * vecs, struct multipath * mpp);
+int update_multipath_strings (struct multipath *mpp, vector pathvec);
+	
+void remove_map (struct multipath * mpp, struct vectors * vecs,
+		 stop_waiter_thread_func *stop_waiter, int purge_vec);
+void remove_maps (struct vectors * vecs,
+		  stop_waiter_thread_func *stop_waiter);
+
+struct multipath * add_map_without_path (struct vectors * vecs,
+				int minor, char * alias,
+				start_waiter_thread_func *start_waiter);
+struct multipath * add_map_with_path (struct vectors * vecs,
+				struct path * pp, int add_vec);
+
+#endif /* _STRUCTS_VEC_H */

Modified: multipath-tools/trunk/libmultipath/switchgroup.c
==============================================================================
--- multipath-tools/trunk/libmultipath/switchgroup.c	(original)
+++ multipath-tools/trunk/libmultipath/switchgroup.c	Mon Mar 13 15:16:41 2006
@@ -1,7 +1,12 @@
+/*
+ * Copyright (c) 2005 Christophe Varoqui
+ * Copyright (c) 2005 Edward Goggin, EMC
+ */
+#include <checkers.h>
+
 #include "vector.h"
 #include "structs.h"
 #include "switchgroup.h"
-#include "../libcheckers/path_state.h"
 
 extern int
 select_path_group (struct multipath * mpp)
@@ -11,6 +16,7 @@
 	int bestpg = 1;
 	struct pathgroup * pgp;
 	struct path * pp;
+	int priority;
 
 	if (!mpp->pg)
 		return 1;
@@ -18,11 +24,14 @@
 	vector_foreach_slot (mpp->pg, pgp, i) {
 		if (!pgp->paths)
 			continue;
-		
+
+		priority = 0;
+
 		vector_foreach_slot (pgp->paths, pp, j) {
 			if (pp->state != PATH_DOWN)
-				pgp->priority += pp->priority;
+				priority += pp->priority;
 		}
+		pgp->priority = priority;
 
 		if (pgp->priority > highest) {
 			highest = pgp->priority;

Modified: multipath-tools/trunk/libmultipath/uevent.c
==============================================================================
--- multipath-tools/trunk/libmultipath/uevent.c	(original)
+++ multipath-tools/trunk/libmultipath/uevent.c	Mon Mar 13 15:16:41 2006
@@ -33,22 +33,103 @@
 #include <sys/user.h>
 #include <asm/types.h>
 #include <linux/netlink.h>
+#include <pthread.h>
+#include <sys/mman.h>
 
 #include "memory.h"
 #include "debug.h"
 #include "uevent.h"
 
+typedef int (uev_trigger)(struct uevent *, void * trigger_data);
+
+pthread_t uevq_thr;
+struct uevent *uevqhp, *uevqtp;
+pthread_mutex_t uevq_lock, *uevq_lockp = &uevq_lock;
+pthread_mutex_t uevc_lock, *uevc_lockp = &uevc_lock;
+pthread_cond_t  uev_cond,  *uev_condp  = &uev_cond;
+uev_trigger *my_uev_trigger;
+void * my_trigger_data;
+
 struct uevent * alloc_uevent (void)
 {
 	return (struct uevent *)MALLOC(sizeof(struct uevent));
 }
 
+void
+service_uevq(void)
+{
+	int empty;
+	struct uevent *uev;
+
+	do {
+		pthread_mutex_lock(uevq_lockp);
+		empty = (uevqhp == NULL);
+		if (!empty) {
+			uev = uevqhp;
+			uevqhp = uev->next;
+			if (uevqtp == uev)
+				uevqtp = uev->next;
+			pthread_mutex_unlock(uevq_lockp);
+
+			if (my_uev_trigger && my_uev_trigger(uev,
+							my_trigger_data))
+				condlog(0, "uevent trigger error");
+
+			FREE(uev);
+		}
+		else {
+			pthread_mutex_unlock(uevq_lockp);
+		}
+	} while (empty == 0);
+}
+
+/*
+ * Service the uevent queue.
+ */
+static void *
+uevq_thread(void * et)
+{
+	mlockall(MCL_CURRENT | MCL_FUTURE);
+
+	while (1) {
+		pthread_mutex_lock(uevc_lockp);
+		pthread_cond_wait(uev_condp, uevc_lockp);
+		pthread_mutex_unlock(uevc_lockp);
+
+		service_uevq();
+	}
+}
+
 int uevent_listen(int (*uev_trigger)(struct uevent *, void * trigger_data),
 		  void * trigger_data)
 {
 	int sock;
 	struct sockaddr_nl snl;
 	int retval;
+	int rcvbufsz = 128*1024;
+	int rcvsz = 0;
+	int rcvszsz = sizeof(rcvsz);
+	unsigned int *prcvszsz = (unsigned int *)&rcvszsz;
+	pthread_attr_t attr;
+
+	my_uev_trigger = uev_trigger;
+	my_trigger_data = trigger_data;
+
+	/*
+	 * Queue uevents for service by dedicated thread so that the uevent
+	 * listening thread does not block on multipathd locks (vecs->lock)
+	 * thereby not getting to empty the socket's receive buffer queue
+	 * often enough.
+	 */
+	uevqhp = uevqtp = NULL;
+
+	pthread_mutex_init(uevq_lockp, NULL);
+	pthread_mutex_init(uevc_lockp, NULL);
+	pthread_cond_init(uev_condp, NULL);
+
+	pthread_attr_init(&attr);
+	pthread_attr_setstacksize(&attr, 64 * 1024);
+	pthread_create(&uevq_thr, &attr, uevq_thread, NULL);
 
 	memset(&snl, 0x00, sizeof(struct sockaddr_nl));
 	snl.nl_family = AF_NETLINK;
@@ -57,35 +138,56 @@
 
 	sock = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);
 	if (sock == -1) {
-		condlog(0, "error getting socket, exit\n");
+		condlog(0, "error getting socket, exit");
 		return 1;
 	}
 
+	/*
+	 * try to avoid dropping uevents, even so, this is not a guarantee,
+	 * but it does help to change the netlink uevent socket's
+	 * receive buffer threshold from the default value of 106,496 to
+	 * the maximum value of 262,142.
+	 */
+	retval = setsockopt(sock, SOL_SOCKET, SO_RCVBUF, &rcvbufsz,
+			    sizeof(rcvbufsz));
+
+	if (retval < 0) {
+		condlog(0, "error setting receive buffer size for socket, exit");
+		exit(1);
+	}
+	retval = getsockopt(sock, SOL_SOCKET, SO_RCVBUF, &rcvsz, prcvszsz);
+
+	if (retval < 0) {
+		condlog(0, "error setting receive buffer size for socket, exit");
+		exit(1);
+	}
+	condlog(3, "receive buffer size for socket is %u.", rcvsz);
+
 	retval = bind(sock, (struct sockaddr *) &snl,
 		      sizeof(struct sockaddr_nl));
 	if (retval < 0) {
-		condlog(0, "bind failed, exit\n");
+		condlog(0, "bind failed, exit");
 		goto exit;
 	}
 
 	while (1) {
-		static char buffer[HOTPLUG_BUFFER_SIZE + OBJECT_SIZE];
+		static char buff[HOTPLUG_BUFFER_SIZE + OBJECT_SIZE];
 		int i;
 		char *pos;
 		size_t bufpos;
 		ssize_t buflen;
 		struct uevent *uev;
+		char *buffer;
 
-		buflen = recv(sock, &buffer, sizeof(buffer), 0);
+		buflen = recv(sock, &buff, sizeof(buff), 0);
 		if (buflen <  0) {
-			condlog(0, "error receiving message\n");
+			condlog(0, "error receiving message");
 			continue;
 		}
 
-		if ((size_t)buflen > sizeof(buffer)-1)
-			buflen = sizeof(buffer)-1;
+		if ((size_t)buflen > sizeof(buff)-1)
+			buflen = sizeof(buff)-1;
 
-		buffer[buflen] = '\0';
 		uev = alloc_uevent();
 
 		if (!uev) {
@@ -93,6 +195,14 @@
 			continue;
 		}
 
+		/*
+		 * Copy the shared receive buffer contents to buffer private
+		 * to this uevent so we can immediately reuse the shared buffer.
+		 */
+		memcpy(uev->buffer, buff, HOTPLUG_BUFFER_SIZE + OBJECT_SIZE);
+		buffer = uev->buffer;
+		buffer[buflen] = '\0';
+
 		/* save start of payload */
 		bufpos = strlen(buffer) + 1;
 
@@ -118,19 +228,39 @@
 		}
 		uev->envp[i] = NULL;
 
-		condlog(3, "uevent '%s' from '%s'\n", uev->action, uev->devpath);
+		condlog(3, "uevent '%s' from '%s'", uev->action, uev->devpath);
 
 		/* print payload environment */
 		for (i = 0; uev->envp[i] != NULL; i++)
-			condlog(3, "%s\n", uev->envp[i]);
+			condlog(3, "%s", uev->envp[i]);
 
-		if (uev_trigger && uev_trigger(uev, trigger_data))
-			condlog(0, "uevent trigger error");
-
-		FREE(uev);
+		/*
+		 * Queue uevent and poke service pthread.
+		 */
+		pthread_mutex_lock(uevq_lockp);
+		if (uevqtp)
+			uevqtp->next = uev;
+		else
+			uevqhp = uev;
+		uevqtp = uev;
+		uev->next = NULL;
+		pthread_mutex_unlock(uevq_lockp);
+
+		pthread_mutex_lock(uevc_lockp);
+		pthread_cond_signal(uev_condp);
+		pthread_mutex_unlock(uevc_lockp);
 	}
 
 exit:
 	close(sock);
+
+	pthread_mutex_lock(uevq_lockp);
+	pthread_cancel(uevq_thr);
+	pthread_mutex_unlock(uevq_lockp);
+
+	pthread_mutex_destroy(uevq_lockp);
+	pthread_mutex_destroy(uevc_lockp);
+	pthread_cond_destroy(uev_condp);
+
 	return 1;
 }

Modified: multipath-tools/trunk/libmultipath/uevent.h
==============================================================================
--- multipath-tools/trunk/libmultipath/uevent.h	(original)
+++ multipath-tools/trunk/libmultipath/uevent.h	Mon Mar 13 15:16:41 2006
@@ -8,6 +8,8 @@
 #endif
 
 struct uevent {
+	void *next;
+	char buffer[HOTPLUG_BUFFER_SIZE + OBJECT_SIZE];
 	char *devpath;
 	char *action;
 	char *envp[HOTPLUG_NUM_ENVP];

Modified: multipath-tools/trunk/libmultipath/uxsock.c
==============================================================================
--- multipath-tools/trunk/libmultipath/uxsock.c	(original)
+++ multipath-tools/trunk/libmultipath/uxsock.c	Mon Mar 13 15:16:41 2006
@@ -1,3 +1,9 @@
+/*
+ * Original author : tridge at samba.org, January 2002
+ *
+ * Copyright (c) 2005 Christophe Varoqui
+ * Copyright (c) 2005 Alasdair Kergon, Redhat
+ */
 #include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>

Modified: multipath-tools/trunk/libmultipath/vector.c
==============================================================================
--- multipath-tools/trunk/libmultipath/vector.c	(original)
+++ multipath-tools/trunk/libmultipath/vector.c	Mon Mar 13 15:16:41 2006
@@ -14,6 +14,9 @@
  *              modify it under the terms of the GNU General Public License
  *              as published by the Free Software Foundation; either version
  *              2 of the License, or (at your option) any later version.
+ *
+ * Copyright (c) 2002, 2003, 2004 Alexandre Cassen
+ * Copyright (c) 2005 Christophe Varoqui
  */
 
 #include "memory.h"

Modified: multipath-tools/trunk/multipath-tools.spec.in
==============================================================================
--- multipath-tools/trunk/multipath-tools.spec.in	(original)
+++ multipath-tools/trunk/multipath-tools.spec.in	Mon Mar 13 15:16:41 2006
@@ -44,11 +44,19 @@
 %{prefix}/sbin/devmap_name
 %{prefix}/sbin/multipath
 %{prefix}/sbin/kpartx
+%{prefix}/sbin/mpath_prio_alua
+%{prefix}/sbin/mpath_prio_emc
+%{prefix}/sbin/mpath_prio_random
+%{prefix}/sbin/mpath_prio_balance_units
+%{prefix}/sbin/mpath_prio_netapp
+%{prefix}/sbin/mpath_prio_tpc
 %{prefix}/usr/share/man/man8/devmap_name.8.gz
 %{prefix}/usr/share/man/man8/multipath.8.gz
-%{prefix}/usr/bin/multipathd
-%{prefix}/etc/hotplug.d/scsi/multipath.hotplug
-%{prefix}/etc/init.d/multipathd
+%{prefix}/usr/share/man/man8/kpartx.8.gz
+%{prefix}/usr/share/man/man8/mpath_prio_alua.8.gz
+%{prefix}/usr/share/man/man8/multipathd.8.gz
+%{prefix}/sbin/multipathd
+%{prefix}/etc/udev/rules.d/multipath.rules
 
 
 %changelog

Modified: multipath-tools/trunk/multipath.conf.annotated
==============================================================================
--- multipath-tools/trunk/multipath.conf.annotated	(original)
+++ multipath-tools/trunk/multipath.conf.annotated	Mon Mar 13 15:16:41 2006
@@ -137,6 +137,10 @@
 #	devnode "^(ram|raw|loop|fd|md|dm-|sr|scd|st)[0-9]*"
 #	devnode "^hd[a-z][[0-9]*]"
 #	devnode "^cciss!c[0-9]d[0-9]*[p[0-9]*]"
+#       device {
+#               vendor DEC.*
+#               product MSA[15]00
+#       }
 #}
 #
 ##
@@ -213,6 +217,15 @@
 #		# default : (null)
 #		#
 #		#no_path_retry  queue
+#
+#		#
+#		# name    : rr_min_io
+#		# scope   : multipath
+#		# desc    : the number of IO to route to a path before switching
+#		#           to the next in the same path group
+#		# default : 1000
+#		#
+#		rr_min_io	100
 #	}
 #	multipath {
 #		wwid	1DEC_____321816758474
@@ -305,6 +318,23 @@
 #		# default : immediate
 #		#
 #		failback		30
+#
+#		#
+#		# name    : rr_min_io
+#		# scope   : multipath
+#		# desc    : the number of IO to route to a path before switching
+#		#           to the next in the same path group
+#		# default : 1000
+#		#
+#		rr_min_io	100
+#
+#		#
+#		# name    : product_blacklist
+#		# scope   : multipath & multipathd
+#		# desc    : product strings to blacklist for this vendor
+#		# default : none
+#		#
+#		product_blacklist	LUN_Z
 #	}
 #	device {
 #		vendor			"COMPAQ  "

Modified: multipath-tools/trunk/multipath.conf.synthetic
==============================================================================
--- multipath-tools/trunk/multipath.conf.synthetic	(original)
+++ multipath-tools/trunk/multipath.conf.synthetic	Mon Mar 13 15:16:41 2006
@@ -14,13 +14,17 @@
 #	rr_weight		priorities
 #	failback		immediate
 #	no_path_retry		fail
-#	user_friendly_name	no
+#	user_friendly_names	no
 #}
 #devnode_blacklist {
 #       wwid 26353900f02796769
 #	devnode "^(ram|raw|loop|fd|md|dm-|sr|scd|st)[0-9]*"
 #	devnode "^hd[a-z][[0-9]*]"
 #	devnode "^cciss!c[0-9]d[0-9]*[p[0-9]*]"
+#	device {
+#		vendor DEC.*
+#		product MSA[15]00
+#	}
 #}
 #multipaths {
 #	multipath {
@@ -32,6 +36,7 @@
 #		failback		manual
 #		rr_weight		priorities
 #		no_path_retry		5
+#		rr_min_io		100
 #	}
 #	multipath {
 #		wwid			1DEC_____321816758474
@@ -50,6 +55,8 @@
 #		failback		15
 #		rr_weight		priorities
 #		no_path_retry		queue
+#		rr_min_io		100
+#		product_blacklist	LUN_Z
 #	}
 #	device {
 #		vendor			"COMPAQ  "

Modified: multipath-tools/trunk/multipath/Makefile
==============================================================================
--- multipath-tools/trunk/multipath/Makefile	(original)
+++ multipath-tools/trunk/multipath/Makefile	Mon Mar 13 15:16:41 2006
@@ -7,13 +7,12 @@
 
 OBJS = main.o $(MULTIPATHLIB)-$(BUILD).a $(CHECKERSLIB)-$(BUILD).a
 
-CFLAGS = -pipe -g -Wall -Wunused -Wstrict-prototypes \
-	 -I$(multipathdir) -I$(checkersdir)
+CFLAGS += -I$(multipathdir) -I$(checkersdir)
 
 ifeq ($(strip $(BUILD)),klibc)
 	OBJS += $(libdm) $(libsysfs)
 else
-	LDFLAGS += -ldevmapper -lsysfs -lm
+	LDFLAGS += -ldevmapper -lsysfs
 endif
 
 EXEC = multipath
@@ -27,7 +26,7 @@
 glibc: prepare $(OBJS)
 	$(CC) $(OBJS) -o $(EXEC) $(LDFLAGS)
 	$(GZIP) $(EXEC).8 > $(EXEC).8.gz
-	
+
 klibc: prepare $(OBJS)
 	$(CC) -static -o $(EXEC) $(CRT0) $(OBJS) $(KLIBC) $(LIBGCC)
 	$(GZIP) $(EXEC).8 > $(EXEC).8.gz

Modified: multipath-tools/trunk/multipath/main.c
==============================================================================
--- multipath-tools/trunk/multipath/main.c	(original)
+++ multipath-tools/trunk/multipath/main.c	Mon Mar 13 15:16:41 2006
@@ -3,7 +3,7 @@
  *
  * Version:     $Id: main.h,v 0.0.1 2003/09/18 15:13:38 cvaroqui Exp $
  *
- * Author:      Copyright (C) 2003 Christophe Varoqui
+ * Author:      Christophe Varoqui
  *
  *              This program is distributed in the hope that it will be useful,
  *              but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -14,270 +14,40 @@
  *              modify it under the terms of the GNU General Public License
  *              as published by the Free Software Foundation; either version
  *              2 of the License, or (at your option) any later version.
+ *
+ * Copyright (c) 2003, 2004, 2005 Christophe Varoqui
+ * Copyright (c) 2005 Benjamin Marzinski, Redhat
+ * Copyright (c) 2005 Kiyoshi Ueda, NEC
+ * Copyright (c) 2005 Patrick Caulfield, Redhat
+ * Copyright (c) 2005 Edward Goggin, EMC
  */
 
 #include <stdio.h>
-#include <stdlib.h>
 #include <unistd.h>
-#include <string.h>
-#include <sys/file.h>
-#include <errno.h>
+#include <ctype.h>
+#include <sysfs/libsysfs.h>
 
-#include <parser.h>
+#include <checkers.h>
 #include <vector.h>
 #include <memory.h>
 #include <libdevmapper.h>
 #include <devmapper.h>
-#include <checkers.h>
-#include <path_state.h>
-#include <blacklist.h>
-#include <hwtable.h>
 #include <util.h>
 #include <defaults.h>
 #include <structs.h>
+#include <structs_vec.h>
 #include <dmparser.h>
-#include <cache.h>
 #include <config.h>
-#include <propsel.h>
+#include <blacklist.h>
 #include <discovery.h>
 #include <debug.h>
 #include <switchgroup.h>
-#include <sysfs/libsysfs.h>
 #include <print.h>
 #include <alias.h>
+#include <configure.h>
+#include <pgpolicies.h>
 
 #include "main.h"
-#include "pgpolicies.h"
-#include "dict.h"
-
-/* for column aligned output */
-struct path_layout pl;
-
-static char *
-get_refwwid (vector pathvec)
-{
-	struct path * pp;
-	char buff[FILE_NAME_SIZE];
-	char * refwwid;
-
-	if (conf->dev_type == DEV_NONE)
-		return NULL;
-
-	if (conf->dev_type == DEV_DEVNODE) {
-		basename(conf->dev, buff);
-		pp = find_path_by_dev(pathvec, buff);
-		
-		if (!pp) {
-			pp = alloc_path();
-
-			if (!pp)
-				return NULL;
-
-			strncpy(pp->dev, buff, FILE_NAME_SIZE);
-
-			if (pathinfo(pp, conf->hwtable, DI_SYSFS | DI_WWID))
-				return NULL;
-
-			if (store_path(pathvec, pp)) {
-				free_path(pp);
-				return NULL;
-			}
-		}
-		refwwid = pp->wwid;
-		goto out;
-	}
-
-	if (conf->dev_type == DEV_DEVT) {
-		pp = find_path_by_devt(pathvec, conf->dev);
-		
-		if (!pp) {
-			if (devt2devname(buff, conf->dev))
-				return NULL;
-
-			pp = alloc_path();
-
-			if (!pp)
-				return NULL;
-
-			strncpy(pp->dev, buff, FILE_NAME_SIZE);
-
-			if (pathinfo(pp, conf->hwtable, DI_SYSFS | DI_WWID))
-				return NULL;
-			
-			if (store_path(pathvec, pp)) {
-				free_path(pp);
-				return NULL;
-			}
-		}
-		refwwid = pp->wwid;
-		goto out;
-	}
-	if (conf->dev_type == DEV_DEVMAP) {
-		/*
-		 * may be a binding
-		 */
-		refwwid = get_user_friendly_wwid(conf->dev,
-						 conf->bindings_file);
-
-		if (refwwid)
-			return refwwid;
-
-		/*
-		 * or may be an alias
-		 */
-		refwwid = get_mpe_wwid(conf->dev);
-
-		/*
-		 * or directly a wwid
-		 */
-		if (!refwwid)
-			refwwid = conf->dev;
-	}
-out:
-	if (refwwid && strlen(refwwid))
-		return STRDUP(refwwid);
-
-	return NULL;
-}
-
-static void
-print_path (struct path * pp, char * style)
-{
-	char line[MAX_LINE_LEN];
-
-	snprint_path(&line[0], MAX_LINE_LEN, style, pp, &pl);
-	printf("%s", line);
-}
-
-static void
-print_map (struct multipath * mpp)
-{
-	if (mpp->size && mpp->params)
-		printf("0 %llu %s %s\n",
-			 mpp->size, DEFAULT_TARGET, mpp->params);
-	return;
-}
-
-static void
-print_all_paths (vector pathvec, int banner)
-{
-	int i;
-	struct path * pp;
-	char line[MAX_LINE_LEN];
-
-	if (!VECTOR_SIZE(pathvec)) {
-		if (banner)
-			fprintf(stdout, "===== no paths =====\n");
-		return;
-	}
-	
-	if (banner)
-		fprintf(stdout, "===== paths list =====\n");
-
-	get_path_layout(&pl, pathvec);
-	snprint_path_header(line, MAX_LINE_LEN, PRINT_PATH_LONG, &pl);
-	fprintf(stdout, "%s", line);
-
-	vector_foreach_slot (pathvec, pp, i)
-		print_path(pp, PRINT_PATH_LONG);
-}
-
-static void
-print_mp (struct multipath * mpp)
-{
-	int j, i;
-	struct path * pp = NULL;
-	struct pathgroup * pgp = NULL;
-
-	if (mpp->action == ACT_NOTHING || !conf->verbosity || !mpp->size)
-		return;
-
-	if (conf->verbosity > 1) {
-		switch (mpp->action) {
-		case ACT_RELOAD:
-			printf("%s: ", ACT_RELOAD_STR);
-			break;
-
-		case ACT_CREATE:
-			printf("%s: ", ACT_CREATE_STR);
-			break;
-
-		case ACT_SWITCHPG:
-			printf("%s: ", ACT_SWITCHPG_STR);
-			break;
-
-		default:
-			break;
-		}
-	}
-
-	if (mpp->alias)
-		printf("%s", mpp->alias);
-
-	if (conf->verbosity == 1) {
-		printf("\n");
-		return;
-	}
-	if (strncmp(mpp->alias, mpp->wwid, WWID_SIZE))
-		printf(" (%s)", mpp->wwid);
-
-	printf("\n");
-
-	if (mpp->size < (1 << 11))
-		printf("[size=%llu kB]", mpp->size >> 1);
-	else if (mpp->size < (1 << 21))
-		printf("[size=%llu MB]", mpp->size >> 11);
-	else if (mpp->size < (1 << 31))
-		printf("[size=%llu GB]", mpp->size >> 21);
-	else
-		printf("[size=%llu TB]", mpp->size >> 31);
-
-	if (mpp->features)
-		printf("[features=\"%s\"]", mpp->features);
-
-	if (mpp->hwhandler)
-		printf("[hwhandler=\"%s\"]", mpp->hwhandler);
-
-	fprintf(stdout, "\n");
-
-	if (!mpp->pg)
-		return;
-
-	vector_foreach_slot (mpp->pg, pgp, j) {
-		printf("\\_ ");
-
-		if (mpp->selector) {
-			printf("%s ", mpp->selector);
-#if 0
-			/* align to path status info */
-			for (i = pl.hbtl_len + pl.dev_len + pl.dev_t_len + 4;
-			     i > strlen(mpp->selector); i--)
-				printf(" ");
-#endif
-		}
-		if (pgp->priority)
-			printf("[prio=%i]", pgp->priority);
-
-		switch (pgp->status) {
-		case PGSTATE_ENABLED:
-			printf("[enabled]");
-			break;
-		case PGSTATE_DISABLED:
-			printf("[disabled]");
-			break;
-		case PGSTATE_ACTIVE:
-			printf("[active]");
-			break;
-		default:
-			break;
-		}
-		printf("\n");
-
-		vector_foreach_slot (pgp->paths, pp, i)
-			print_path(pp, PRINT_PATH_INDENT);
-	}
-	printf("\n");
-}
 
 static int
 filter_pathvec (vector pathvec, char * refwwid)
@@ -299,535 +69,6 @@
 	return 0;
 }
 
-/*
- * Transforms the path group vector into a proper device map string
- */
-int
-assemble_map (struct multipath * mp)
-{
-	int i, j;
-	int shift, freechar;
-	int minio;
-	char * p;
-	struct pathgroup * pgp;
-	struct path * pp;
-
-	p = mp->params;
-	freechar = sizeof(mp->params);
-	
-	shift = snprintf(p, freechar, "%s %s %i %i",
-			 mp->features, mp->hwhandler,
-			 VECTOR_SIZE(mp->pg), mp->bestpg);
-
-	if (shift >= freechar) {
-		fprintf(stderr, "mp->params too small\n");
-		return 1;
-	}
-	p += shift;
-	freechar -= shift;
-	
-	vector_foreach_slot (mp->pg, pgp, i) {
-		pgp = VECTOR_SLOT(mp->pg, i);
-		shift = snprintf(p, freechar, " %s %i 1", mp->selector,
-				 VECTOR_SIZE(pgp->paths));
-		if (shift >= freechar) {
-			fprintf(stderr, "mp->params too small\n");
-			return 1;
-		}
-		p += shift;
-		freechar -= shift;
-
-		vector_foreach_slot (pgp->paths, pp, j) {
-			minio = conf->minio;
-			
-			if (mp->rr_weight == RR_WEIGHT_PRIO && pp->priority)
-				minio *= pp->priority;
-
-			shift = snprintf(p, freechar, " %s %d",
-					 pp->dev_t, minio);
-			if (shift >= freechar) {
-				fprintf(stderr, "mp->params too small\n");
-				return 1;
-			}
-			p += shift;
-			freechar -= shift;
-		}
-	}
-	if (freechar < 1) {
-		fprintf(stderr, "mp->params too small\n");
-		return 1;
-	}
-	snprintf(p, 1, "\n");
-
-	if (conf->verbosity > 2)
-		print_map(mp);
-
-	return 0;
-}
-
-static int
-setup_map (struct multipath * mpp)
-{
-	/*
-	 * don't bother if devmap size is unknown
-	 */
-	if (mpp->size <= 0) {
-		condlog(3, "%s devmap size is unknown", mpp->alias);
-		return 1;
-	}
-
-	/*
-	 * properties selectors
-	 */
-	select_pgpolicy(mpp);
-	select_selector(mpp);
-	select_features(mpp);
-	select_hwhandler(mpp);
-	select_rr_weight(mpp);
-	select_no_path_retry(mpp);
-
-	/*
-	 * apply selected grouping policy to valid paths
-	 */
-	switch (mpp->pgpolicy) {
-	case MULTIBUS:
-		one_group(mpp);
-		break;
-	case FAILOVER:
-		one_path_per_group(mpp);
-		break;
-	case GROUP_BY_SERIAL:
-		group_by_serial(mpp);
-		break;
-	case GROUP_BY_PRIO:
-		group_by_prio(mpp);
-		break;
-	case GROUP_BY_NODE_NAME:
-		group_by_node_name(mpp);
-		break;
-	default:
-		break;
-	}
-
-	if (mpp->pg == NULL) {
-		condlog(3, "pgpolicy failed to produce a pg vector");
-		return 1;
-	}
-
-	/*
-	 * ponders each path group and determine highest prio pg
-	 * to switch over (default to first)
-	 */
-	mpp->bestpg = select_path_group(mpp);
-
-	/*
-	 * transform the mp->pg vector of vectors of paths
-	 * into a mp->params strings to feed the device-mapper
-	 */
-	if (assemble_map(mpp)) {
-		condlog(3, "problem assembing map");
-		return 1;
-	}
-	return 0;
-}
-
-static int
-pathcount (struct multipath * mpp, int state)
-{
-	struct pathgroup *pgp;
-	struct path *pp;
-	int i, j;
-	int count = 0;
-
-	vector_foreach_slot (mpp->pg, pgp, i)
-		vector_foreach_slot (pgp->paths, pp, j)
-			if (pp->state == state)
-				count++;
-	return count;
-}
-
-static void
-compute_pgid(struct pathgroup * pgp)
-{
-	struct path * pp;
-	int i;
-
-	vector_foreach_slot (pgp->paths, pp, i)
-		pgp->id ^= (long)pp;
-}
-
-static int
-pgcmp (struct multipath * mpp, struct multipath * cmpp)
-{
-	int i, j;
-	struct pathgroup * pgp;
-	struct pathgroup * cpgp;
-	int r = 0;
-
-	vector_foreach_slot (mpp->pg, pgp, i) {
-		compute_pgid(pgp);
-
-		vector_foreach_slot (cmpp->pg, cpgp, j) {
-			if (pgp->id == cpgp->id) {
-				r = 0;
-				break;
-			}
-			r++;
-		}
-		if (r)
-			return r;
-	}
-	return r;
-}
-
-static void
-select_action (struct multipath * mpp, vector curmp)
-{
-	struct multipath * cmpp;
-
-	cmpp = find_mp_by_alias(curmp, mpp->alias);
-
-	if (!cmpp) {
-		cmpp = find_mp_by_wwid(curmp, mpp->wwid);
-
-		if (cmpp && !conf->dry_run) {
-			condlog(2, "remove: %s (dup of %s)",
-				cmpp->alias, mpp->alias);
-			dm_flush_map(cmpp->alias, DEFAULT_TARGET);
-		}
-		mpp->action = ACT_CREATE;
-		condlog(3, "set ACT_CREATE: map does not exists");
-		return;
-	}
-
-	if (!find_mp_by_wwid(curmp, mpp->wwid)) {
-		condlog(2, "remove: %s (wwid changed)", cmpp->alias);
-		dm_flush_map(mpp->alias, NULL);
-		strncat(cmpp->wwid, mpp->wwid, WWID_SIZE);
-		drop_multipath(curmp, cmpp->wwid, KEEP_PATHS);
-		mpp->action = ACT_CREATE;
-		condlog(3, "set ACT_CREATE: map wwid change");
-		return;
-	}
-		
-	if (pathcount(mpp, PATH_UP) == 0) {
-		mpp->action = ACT_NOTHING;
-		condlog(3, "set ACT_NOTHING: no usable path");
-		return;
-	}
-	if (cmpp->size != mpp->size) {
-		mpp->action = ACT_RELOAD;
-		condlog(3, "set ACT_RELOAD: size change");
-		return;
-	}
-	if (!mpp->no_path_retry && /* let features be handled by the daemon */
-	    strncmp(cmpp->features, mpp->features, strlen(mpp->features))) {
-		mpp->action =  ACT_RELOAD;
-		condlog(3, "set ACT_RELOAD: features change");
-		return;
-	}
-	if (strncmp(cmpp->hwhandler, mpp->hwhandler,
-		    strlen(mpp->hwhandler))) {
-		mpp->action = ACT_RELOAD;
-		condlog(3, "set ACT_RELOAD: hwhandler change");
-		return;
-	}
-	if (strncmp(cmpp->selector, mpp->selector,
-		    strlen(mpp->selector))) {
-		mpp->action = ACT_RELOAD;
-		condlog(3, "set ACT_RELOAD: selector change");
-		return;
-	}
-	if (VECTOR_SIZE(cmpp->pg) != VECTOR_SIZE(mpp->pg)) {
-		mpp->action = ACT_RELOAD;
-		condlog(3, "set ACT_RELOAD: number of path group change");
-		return;
-	}
-	if (pgcmp(mpp, cmpp)) {
-		mpp->action = ACT_RELOAD;
-		condlog(3, "set ACT_RELOAD: path group topology change");
-		return;
-	}
-	if (cmpp->nextpg != mpp->bestpg) {
-		mpp->action = ACT_SWITCHPG;
-		condlog(3, "set ACT_SWITCHPG: next path group change");
-		return;
-	}
-	mpp->action = ACT_NOTHING;
-	condlog(3, "set ACT_NOTHING: map unchanged");
-	return;
-}
-
-static int
-reinstate_paths (struct multipath * mpp)
-{
-	int i, j;
-	struct pathgroup * pgp;
-	struct path * pp;
-
-	if (!mpp->pg)
-		return 0;
-
-	vector_foreach_slot (mpp->pg, pgp, i) {
-		if (!pgp->paths)
-			continue;
-
-		vector_foreach_slot (pgp->paths, pp, j) {
-			if (pp->state != PATH_UP &&
-			    (pgp->status == PGSTATE_DISABLED ||
-			     pgp->status == PGSTATE_ACTIVE))
-				continue;
-
-			if (pp->dmstate == PSTATE_FAILED) {
-				if (dm_reinstate_path(mpp->alias, pp->dev_t))
-					condlog(0, "error reinstating %s",
-						pp->dev);
-			}
-		}
-	}
-	return 0;
-}
-
-int lock_multipath (struct multipath * mpp, int lock)
-{
-	struct pathgroup * pgp;
-	struct path * pp;
-	int i, j;
-
-	if (!mpp || !mpp->pg)
-		return 0;
-	
-	vector_foreach_slot (mpp->pg, pgp, i) {
-		if (!pgp->paths)
-			continue;
-		vector_foreach_slot(pgp->paths, pp, j) {
-			if (lock && flock(pp->fd, LOCK_EX | LOCK_NB) &&
-			    errno == EWOULDBLOCK)
-				return 1;
-			else if (!lock)
-				flock(pp->fd, LOCK_UN);
-		}
-	}
-	return 0;
-}
-
-/*
- * Return value:
- *  -1: Retry
- *   0: DM_DEVICE_CREATE or DM_DEVICE_RELOAD failed, or dry_run mode.
- *   1: DM_DEVICE_CREATE or DM_DEVICE_RELOAD succeeded.
- *   2: Map is already existing.
- */
-static int
-domap (struct multipath * mpp)
-{
-	int r = 0;
-
-	/*
-	 * last chance to quit before touching the devmaps
-	 */
-	if (conf->dry_run) {
-		print_mp(mpp);
-		return 0;
-	}
-
-	switch (mpp->action) {
-	case ACT_NOTHING:
-		return 2;
-
-	case ACT_SWITCHPG:
-		dm_switchgroup(mpp->alias, mpp->bestpg);
-		/*
-		 * we may have avoided reinstating paths because there where in
-		 * active or disabled PG. Now that the topology has changed,
-		 * retry.
-		 */
-		reinstate_paths(mpp);
-		return 2;
-
-	case ACT_CREATE:
-		if (lock_multipath(mpp, 1)) {
-			condlog(3, "%s: in use", mpp->alias);
-			return -1;
-		}
-		dm_shut_log();
-
-		if (dm_map_present(mpp->alias))
-			break;
-
-		r = dm_addmap(DM_DEVICE_CREATE, mpp->alias, DEFAULT_TARGET,
-			      mpp->params, mpp->size, mpp->wwid);
-
-		/*
-		 * DM_DEVICE_CREATE is actually DM_DEV_CREATE plus
-		 * DM_TABLE_LOAD. Failing the second part leaves an
-		 * empty map. Clean it up.
-		 */
-		if (!r && dm_map_present(mpp->alias)) {
-			condlog(3, "%s: failed to load map "
-				   "(a path might be in use)",
-				   mpp->alias);
-			dm_flush_map(mpp->alias, NULL);
-		}
-
-		lock_multipath(mpp, 0);
-		dm_restore_log();
-		break;
-
-	case ACT_RELOAD:
-		r = (dm_addmap(DM_DEVICE_RELOAD, mpp->alias, DEFAULT_TARGET,
-			      mpp->params, mpp->size, NULL) &&
-		     dm_simplecmd(DM_DEVICE_RESUME, mpp->alias));
-		break;
-
-	default:
-		break;
-	}
-
-	if (r) {
-		/*
-		 * DM_DEVICE_CREATE or DM_DEVICE_RELOAD succeeded
-		 */
-		dm_switchgroup(mpp->alias, mpp->bestpg);
-		print_mp(mpp);
-	}
-
-	return r;
-}
-
-static int
-deadmap (struct multipath * mpp)
-{
-	int i, j;
-	struct pathgroup * pgp;
-	struct path * pp;
-
-	if (!mpp->pg)
-		return 1;
-
-	vector_foreach_slot (mpp->pg, pgp, i) {
-		if (!pgp->paths)
-			continue;
-
-		vector_foreach_slot (pgp->paths, pp, j)
-			if (strlen(pp->dev))
-				return 0; /* alive */
-	}
-	
-	return 1; /* dead */
-}
-
-static int
-coalesce_paths (vector curmp, vector pathvec)
-{
-	int r = 1;
-	int k, i;
-	char empty_buff[WWID_SIZE];
-	struct multipath * mpp;
-	struct path * pp1;
-	struct path * pp2;
-
-	memset(empty_buff, 0, WWID_SIZE);
-
-	vector_foreach_slot (pathvec, pp1, k) {
-		/* skip this path for some reason */
-
-		/* 1. if path has no unique id or wwid blacklisted */
-		if (memcmp(empty_buff, pp1->wwid, WWID_SIZE) == 0 ||
-		    blacklist(conf->blist, pp1->wwid))
-			continue;
-
-		/* 2. if path already coalesced */
-		if (pp1->mpp)
-			continue;
-
-		/*
-		 * at this point, we know we really got a new mp
-		 */
-		mpp = alloc_multipath();
-
-		if (!mpp)
-			return 1;
-
-		mpp->mpe = find_mpe(pp1->wwid);
-		mpp->hwe = pp1->hwe;
-		strcpy(mpp->wwid, pp1->wwid);
-		select_alias(mpp);
-
-		pp1->mpp = mpp;
-		mpp->size = pp1->size;
-		mpp->paths = vector_alloc();
-
-		if (pp1->priority < 0)
-			mpp->action = ACT_NOTHING;
-
-		if (!mpp->paths)
-			return 1;
-		
-		if (store_path(mpp->paths, pp1))
-			return 1;
-
-		for (i = k + 1; i < VECTOR_SIZE(pathvec); i++) {
-			pp2 = VECTOR_SLOT(pathvec, i);
-
-			if (strcmp(pp1->wwid, pp2->wwid))
-				continue;
-			
-			pp2->mpp = mpp;
-
-			if (pp2->size != mpp->size) {
-				/*
-				 * ouch, avoid feeding that to the DM
-				 */
-				condlog(3, "path size mismatch : discard %s",
-				     mpp->wwid);
-				mpp->action = ACT_NOTHING;
-			}
-			if (pp2->priority < 0)
-				mpp->action = ACT_NOTHING;
-
-			if (store_path(mpp->paths, pp2))
-				return 1;
-		}
-		if (setup_map(mpp))
-			goto next;
-
-		if (mpp->action == ACT_UNDEF)
-			select_action(mpp, curmp);
-
-		r = domap(mpp);
-
-		if (r < 0)
-			return r;
-
-		if (r && mpp->no_path_retry != NO_PATH_RETRY_UNDEF) {
-			if (mpp->no_path_retry == NO_PATH_RETRY_FAIL)
-				dm_queue_if_no_path(mpp->alias, 0);
-			else
-				dm_queue_if_no_path(mpp->alias, 1);
-		}
-
-next:
-		drop_multipath(curmp, mpp->wwid, KEEP_PATHS);
-		free_multipath(mpp, KEEP_PATHS);
-	}
-	/*
-	 * Flush maps with only dead paths (ie not in sysfs)
-	 * Keep maps with only failed paths
-	 */
-	vector_foreach_slot (curmp, mpp, i) {
-		if (!deadmap(mpp))
-			continue;
-
-		if (dm_flush_map(mpp->alias, DEFAULT_TARGET))
-			condlog(2, "remove: %s (dead) failed!",
-				mpp->alias);
-		else
-			condlog(2, "remove: %s (dead)", mpp->alias);
-	}
-	return 0;
-}
-
 static void
 usage (char * progname)
 {
@@ -887,9 +128,7 @@
 					pp->state = PATH_DOWN;
 					continue;
 				}
-				pathinfo(pp, conf->hwtable,
-					 DI_SYSFS | DI_CHECKER | \
-					 DI_SERIAL | DI_PRIO);
+				pathinfo(pp, conf->hwtable, DI_ALL);
 				continue;
 			}
 			if (pp->state == PATH_UNCHECKED)
@@ -943,7 +182,7 @@
 		disassemble_status(mpp->status, mpp);
 
 		if (conf->list)
-			print_mp(mpp);
+			print_multipath_topology(mpp, conf->verbosity);
 
 		if (!conf->dry_run)
 			reinstate_paths(mpp);
@@ -963,6 +202,7 @@
 {
 	vector curmp = NULL;
 	vector pathvec = NULL;
+	struct vectors vecs;
 	int r = 1;
 	int di_flag = 0;
 	char * refwwid = NULL;
@@ -978,6 +218,8 @@
 		condlog(0, "can not allocate memory");
 		goto out;
 	}
+	vecs.pathvec = pathvec;
+	vecs.mpvec = curmp;
 
 	/*
 	 * if we have a blacklisted device parameter, exit early
@@ -990,27 +232,24 @@
 			dev = conf->dev;
 	}
 	
-	if (dev && blacklist(conf->blist, dev))
+	if (dev && blacklist(conf->blist_devnode, dev))
 		goto out;
 	
-	condlog(3, "load path identifiers cache");
-	cache_load(pathvec);
-
-	if (conf->verbosity > 2)
-		print_all_paths(pathvec, 1);
-
 	/*
 	 * scope limiting must be translated into a wwid
 	 * failing the translation is fatal (by policy)
 	 */
 	if (conf->dev) {
-		refwwid = get_refwwid(pathvec);
+		refwwid = get_refwwid(conf->dev, conf->dev_type, pathvec);
 
 		if (!refwwid) {
 			condlog(3, "scope is nul");
 			goto out;
 		}
 		condlog(3, "scope limited to %s", refwwid);
+
+		if (blacklist(conf->blist_wwid, refwwid))
+			goto out;
 	}
 
 	/*
@@ -1035,7 +274,7 @@
 	if (conf->verbosity > 2)
 		print_all_paths(pathvec, 1);
 
-	get_path_layout(&pl, pathvec);
+	get_path_layout(pathvec);
 
 	if (get_dm_mpvec(curmp, pathvec, refwwid))
 		goto out;
@@ -1048,7 +287,7 @@
 	/*
 	 * core logic entry point
 	 */
-	r = coalesce_paths(curmp, pathvec);
+	r = coalesce_paths(&vecs, NULL, NULL);
 
 out:
 	if (refwwid)

Modified: multipath-tools/trunk/multipath/main.h
==============================================================================
--- multipath-tools/trunk/multipath/main.h	(original)
+++ multipath-tools/trunk/multipath/main.h	Mon Mar 13 15:16:41 2006
@@ -20,31 +20,12 @@
 #define _MAIN_H
 
 /*
- * configurator actions
- */
-#define ACT_NOTHING_STR		"unchanged"
-#define ACT_RELOAD_STR		"reload"
-#define ACT_SWITCHPG_STR	"switchpg"
-#define ACT_CREATE_STR		"create"
-
-enum actions {
-	ACT_UNDEF,
-	ACT_NOTHING,
-	ACT_RELOAD,
-	ACT_SWITCHPG,
-	ACT_CREATE
-};
-
-#define FLUSH_ONE 1
-#define FLUSH_ALL 2
-
-/*
  * Build version
  */
 #define PROG    "multipath"
 
-#define VERSION_CODE 0x000406
-#define DATE_CODE    0x0b0a05
+#define VERSION_CODE 0x000407
+#define DATE_CODE    0x030c06
 
 #define MULTIPATH_VERSION(version)	\
 	(version >> 16) & 0xFF,		\

Modified: multipath-tools/trunk/multipath/multipath.rules
==============================================================================
--- multipath-tools/trunk/multipath/multipath.rules	(original)
+++ multipath-tools/trunk/multipath/multipath.rules	Mon Mar 13 15:16:41 2006
@@ -8,7 +8,3 @@
 	PROGRAM="/sbin/dmsetup -j %M -m %m --noopencount --noheadings -c -o name info", \
 	RUN+="/sbin/kpartx -a /dev/mapper/%c"
 
-# insert new paths in multipath topology
-ACTION=="add", SUBSYSTEM=="block", KERNEL!="dm-*", \
-	RUN+="/sbin/multipath -v0 %r/%k"
-

Modified: multipath-tools/trunk/multipathd/Makefile
==============================================================================
--- multipath-tools/trunk/multipathd/Makefile	(original)
+++ multipath-tools/trunk/multipathd/Makefile	Mon Mar 13 15:16:41 2006
@@ -4,18 +4,10 @@
 include ../Makefile.inc
 
 #
-# directories where to put stuff
-#
-bindir = /usr/bin
-mandir = /usr/share/man/man8
-rcdir = /etc/init.d
-
-#
 # basic flags setting
 #
-CFLAGS = -pipe -g -Wall -Wunused -Wstrict-prototypes \
-	 -DDAEMON -I$(multipathdir) -I$(checkersdir)
-LDFLAGS = -lpthread -ldevmapper -lsysfs -lreadline -lncurses -lm
+CFLAGS += -DDAEMON -I$(multipathdir) -I$(checkersdir)
+LDFLAGS = -lpthread -ldevmapper -lsysfs -lreadline -lncurses
 
 #
 # debuging stuff

Modified: multipath-tools/trunk/multipathd/cli.c
==============================================================================
--- multipath-tools/trunk/multipathd/cli.c	(original)
+++ multipath-tools/trunk/multipathd/cli.c	Mon Mar 13 15:16:41 2006
@@ -1,3 +1,6 @@
+/*
+ * Copyright (c) 2005 Christophe Varoqui
+ */
 #include <memory.h>
 #include <vector.h>
 #include <util.h>
@@ -127,12 +130,16 @@
 	r += add_key(keys, "fail", FAIL, 0);
 	r += add_key(keys, "paths", PATHS, 0);
 	r += add_key(keys, "maps", MAPS, 0);
+	r += add_key(keys, "multipaths", MAPS, 0);
 	r += add_key(keys, "path", PATH, 1);
 	r += add_key(keys, "map", MAP, 1);
+	r += add_key(keys, "multipath", MAP, 1);
 	r += add_key(keys, "group", GROUP, 1);
-	r += add_key(keys, "dump", DUMP, 0);
-	r += add_key(keys, "pathvec", PATHVEC, 0);
 	r += add_key(keys, "reconfigure", RECONFIGURE, 0);
+	r += add_key(keys, "status", STATUS, 0);
+	r += add_key(keys, "stats", STATS, 0);
+	r += add_key(keys, "topology", TOPOLOGY, 0);
+	r += add_key(keys, "config", CONFIG, 0);
 
 	if (r) {
 		free_keys(keys);
@@ -147,14 +154,26 @@
 find_key (char * str)
 {
 	int i;
+	int len, klen;
 	struct key * kw = NULL;
+	struct key * foundkw = NULL;
 
-	vector_foreach_slot (keys, kw, i)
-		if (strlen(str) == strlen(kw->str) &&
-		    !strcmp(kw->str, str))
-				return kw;
-
-	return NULL;
+	vector_foreach_slot (keys, kw, i) {
+		len = strlen(str);
+		klen = strlen(kw->str);
+
+		if (strncmp(kw->str, str, len))
+			continue;
+		else if (len == klen)
+			return kw; /* exact match */
+		else if (len < klen) {
+			if (!foundkw)
+				foundkw = kw; /* shortcut match */
+			else
+				return NULL; /* ambiguous word */
+		}
+	}
+	return foundkw;
 }
 		
 static struct handler *
@@ -280,7 +299,7 @@
 	char * reply;
 	char * p;
 
-	reply = MALLOC(MAX_REPLY_LEN);
+	reply = MALLOC(INITIAL_REPLY_LEN);
 
 	if (!reply)
 		return NULL;

Modified: multipath-tools/trunk/multipathd/cli.h
==============================================================================
--- multipath-tools/trunk/multipathd/cli.h	(original)
+++ multipath-tools/trunk/multipathd/cli.h	Mon Mar 13 15:16:41 2006
@@ -12,9 +12,11 @@
 	__PATH,
 	__MAP,
 	__GROUP,
-	__DUMP,
-	__PATHVEC,
-	__RECONFIGURE
+	__RECONFIGURE,
+	__STATUS,
+	__STATS,
+	__TOPOLOGY,
+	__CONFIG,
 };
 
 #define LIST		(1 << __LIST)
@@ -30,11 +32,13 @@
 #define PATH		(1 << __PATH)
 #define MAP		(1 << __MAP)
 #define GROUP		(1 << __GROUP)
-#define DUMP		(1 << __DUMP)
-#define PATHVEC		(1 << __PATHVEC)
 #define RECONFIGURE	(1 << __RECONFIGURE)
+#define STATUS		(1 << __STATUS)
+#define STATS		(1 << __STATS)
+#define TOPOLOGY	(1 << __TOPOLOGY)
+#define CONFIG		(1 << __CONFIG)
 
-#define MAX_REPLY_LEN 1000
+#define INITIAL_REPLY_LEN 1000
 
 struct key {
 	char * str;

Modified: multipath-tools/trunk/multipathd/cli_handlers.c
==============================================================================
--- multipath-tools/trunk/multipathd/cli_handlers.c	(original)
+++ multipath-tools/trunk/multipathd/cli_handlers.c	Mon Mar 13 15:16:41 2006
@@ -1,20 +1,242 @@
+/*
+ * Copyright (c) 2005 Christophe Varoqui
+ */
+#include <checkers.h>
 #include <memory.h>
 #include <vector.h>
 #include <structs.h>
+#include <structs_vec.h>
 #include <libdevmapper.h>
 #include <devmapper.h>
 #include <config.h>
+#include <configure.h>
 #include <blacklist.h>
+#include <debug.h>
+#include <print.h>
 
 #include "main.h"
 #include "cli.h"
 
 int
+show_paths (char ** r, int * len, struct vectors * vecs, char * style)
+{
+	int i;
+	struct path * pp;
+	char * c;
+	char * reply;
+	unsigned int maxlen = INITIAL_REPLY_LEN;
+	int again = 1;
+
+	get_path_layout(vecs->pathvec);
+	reply = MALLOC(maxlen);
+
+	while (again) {
+		if (!reply)
+			return 1;
+
+		c = reply;
+
+		if (VECTOR_SIZE(vecs->pathvec) > 0)
+			c += snprint_path_header(c, reply + maxlen - c,
+						 style);
+
+		vector_foreach_slot(vecs->pathvec, pp, i)
+			c += snprint_path(c, reply + maxlen - c,
+					  style, pp);
+
+		again = ((c - reply) == (maxlen - 1));
+
+		if (again)
+			reply = REALLOC(reply, maxlen *= 2);
+
+	}
+	*r = reply;
+	*len = (int)(c - reply + 1);
+	return 0;
+}
+
+int
+show_map_topology (char ** r, int * len, struct multipath * mpp)
+{
+	char * c;
+	char * reply;
+	unsigned int maxlen = INITIAL_REPLY_LEN;
+	int again = 1;
+
+	reply = MALLOC(maxlen);
+
+	while (again) {
+		if (!reply)
+			return 1;
+
+		c = reply;
+
+		c += snprint_multipath_topology( c, reply + maxlen - c, mpp, 2);
+		again = ((c - reply) == (maxlen - 1));
+
+		if (again)
+			reply = REALLOC(reply, maxlen *= 2);
+
+	}
+	*r = reply;
+	*len = (int)(c - reply + 1);
+	return 0;
+}
+
+int
+show_maps_topology (char ** r, int * len, struct vectors * vecs)
+{
+	int i;
+	struct multipath * mpp;
+	char * c;
+	char * reply;
+	unsigned int maxlen = INITIAL_REPLY_LEN;
+	int again = 1;
+
+	reply = MALLOC(maxlen);
+
+	while (again) {
+		if (!reply)
+			return 1;
+
+		c = reply;
+
+		vector_foreach_slot(vecs->mpvec, mpp, i)
+			c += snprint_multipath_topology(c, reply + maxlen - c,
+							mpp, 2);
+
+		again = ((c - reply) == (maxlen - 1));
+
+		if (again)
+			reply = REALLOC(reply, maxlen *= 2);
+
+	}
+	*r = reply;
+	*len = (int)(c - reply + 1);
+	return 0;
+}
+
+int
+show_config (char ** r, int * len)
+{
+	char * c;
+	char * reply;
+	unsigned int maxlen = INITIAL_REPLY_LEN;
+	int again = 1;
+
+	reply = MALLOC(maxlen);
+
+	while (again) {
+		if (!reply)
+			return 1;
+		c = reply;
+		c += snprint_defaults(c, reply + maxlen - c);
+		again = ((c - reply) == maxlen);
+		if (again) {
+			reply = REALLOC(reply, maxlen *= 2);
+			continue;
+		}
+		c += snprint_blacklist(c, reply + maxlen - c);
+		again = ((c - reply) == maxlen);
+		if (again) {
+			reply = REALLOC(reply, maxlen *= 2);
+			continue;
+		}
+		c += snprint_hwtable(c, reply + maxlen - c, conf->hwtable);
+		again = ((c - reply) == maxlen);
+		if (again) {
+			reply = REALLOC(reply, maxlen *= 2);
+			continue;
+		}
+		c += snprint_mptable(c, reply + maxlen - c, conf->mptable);
+		again = ((c - reply) == maxlen);
+		if (again)
+			reply = REALLOC(reply, maxlen *= 2);
+	}
+	*r = reply;
+	*len = (int)(c - reply + 1);
+	return 0;
+}
+
+int
+cli_list_config (void * v, char ** reply, int * len, void * data)
+{
+	condlog(3, "list config (operator)");
+
+	return show_config(reply, len);
+}
+
+int
 cli_list_paths (void * v, char ** reply, int * len, void * data)
 {
 	struct vectors * vecs = (struct vectors *)data;
 
-	return show_paths(reply, len, vecs);
+	condlog(3, "list paths (operator)");
+
+	return show_paths(reply, len, vecs, PRINT_PATH_CHECKER);
+}
+
+int
+cli_list_map_topology (void * v, char ** reply, int * len, void * data)
+{
+	struct multipath * mpp;
+	struct vectors * vecs = (struct vectors *)data;
+	char * param = get_keyparam(v, MAP);
+	
+	mpp = find_mp_by_str(vecs->mpvec, param);
+
+	if (!mpp)
+		return 1;
+
+	condlog(3, "list multipath %s (operator)", param);
+
+	return show_map_topology(reply, len, mpp);
+}
+
+int
+cli_list_maps_topology (void * v, char ** reply, int * len, void * data)
+{
+	struct vectors * vecs = (struct vectors *)data;
+
+	condlog(3, "list multipaths (operator)");
+
+	return show_maps_topology(reply, len, vecs);
+}
+
+int
+show_maps (char ** r, int *len, struct vectors * vecs, char * style)
+{
+	int i;
+	struct multipath * mpp;
+	char * c;
+	char * reply;
+	unsigned int maxlen = INITIAL_REPLY_LEN;
+	int again = 1;
+
+	get_multipath_layout(vecs->mpvec);
+	reply = MALLOC(maxlen);
+
+	while (again) {
+		if (!reply)
+			return 1;
+
+		c = reply;
+		if (VECTOR_SIZE(vecs->mpvec) > 0)
+			c += snprint_multipath_header(c, reply + maxlen - c,
+						      style);
+
+		vector_foreach_slot(vecs->mpvec, mpp, i)
+			c += snprint_multipath(c, reply + maxlen - c,
+					       style, mpp);
+
+		again = ((c - reply) == (maxlen - 1));
+
+		if (again)
+			reply = REALLOC(reply, maxlen *= 2);
+	}
+	*r = reply;
+	*len = (int)(c - reply + 1);
+	return 0;
 }
 
 int
@@ -22,7 +244,29 @@
 {
 	struct vectors * vecs = (struct vectors *)data;
 
-	return show_maps(reply, len, vecs);
+	condlog(3, "list maps (operator)");
+
+	return show_maps(reply, len, vecs, PRINT_MAP_NAMES);
+}
+
+int
+cli_list_maps_status (void * v, char ** reply, int * len, void * data)
+{
+	struct vectors * vecs = (struct vectors *)data;
+
+	condlog(3, "list maps status (operator)");
+
+	return show_maps(reply, len, vecs, PRINT_MAP_STATUS);
+}
+
+int
+cli_list_maps_stats (void * v, char ** reply, int * len, void * data)
+{
+	struct vectors * vecs = (struct vectors *)data;
+
+	condlog(3, "list maps stats (operator)");
+
+	return show_maps(reply, len, vecs, PRINT_MAP_STATS);
 }
 
 int
@@ -30,13 +274,18 @@
 {
 	struct vectors * vecs = (struct vectors *)data;
 	char * param = get_keyparam(v, PATH);
+	int r;
+
+	condlog(2, "%s: add path (operator)", param);
 
-	if (blacklist(conf->blist, param)) {
+	if (blacklist(conf->blist_devnode, param) ||
+	    (r = ev_add_path(param, vecs)) == 2) {
 		*reply = strdup("blacklisted");
 		*len = strlen(*reply) + 1;
+		condlog(2, "%s: path blacklisted", param);
 		return 0;
 	}
-	return uev_add_path(param, vecs);
+	return r;
 }
 
 int
@@ -45,7 +294,9 @@
 	struct vectors * vecs = (struct vectors *)data;
 	char * param = get_keyparam(v, PATH);
 
-	return uev_remove_path(param, vecs);
+	condlog(2, "%s: remove path (operator)", param);
+
+	return ev_remove_path(param, vecs);
 }
 
 int
@@ -54,7 +305,15 @@
 	struct vectors * vecs = (struct vectors *)data;
 	char * param = get_keyparam(v, MAP);
 
-	return uev_add_map(param, vecs);
+	condlog(2, "%s: add map (operator)", param);
+
+	if (blacklist(conf->blist_wwid, param)) {
+		*reply = strdup("blacklisted");
+		*len = strlen(*reply) + 1;
+		condlog(2, "%s: map blacklisted", param);
+		return 0;
+	}
+	return ev_add_map(param, vecs);
 }
 
 int
@@ -63,7 +322,9 @@
 	struct vectors * vecs = (struct vectors *)data;
 	char * param = get_keyparam(v, MAP);
 
-	return uev_remove_map(param, vecs);
+	condlog(2, "%s: remove map (operator)", param);
+
+	return ev_remove_map(param, vecs);
 }
 
 int
@@ -72,15 +333,9 @@
 	char * mapname = get_keyparam(v, MAP);
 	int groupnum = atoi(get_keyparam(v, GROUP));
 	
-	return dm_switchgroup(mapname, groupnum);
-}
+	condlog(2, "%s: switch to path group #%i (operator)", mapname, groupnum);
 
-int
-cli_dump_pathvec(void * v, char ** reply, int * len, void * data)
-{
-	struct vectors * vecs = (struct vectors *)data;
-			
-	return dump_pathvec(reply, len, vecs);
+	return dm_switchgroup(mapname, groupnum);
 }
 
 int
@@ -88,6 +343,8 @@
 {
 	struct vectors * vecs = (struct vectors *)data;
 			
+	condlog(2, "reconfigure (operator)");
+
 	return reconfigure(vecs);
 }
 
@@ -98,6 +355,8 @@
 	char * param = get_keyparam(v, MAP);
 	int r = dm_simplecmd(DM_DEVICE_SUSPEND, param);
 
+	condlog(2, "%s: suspend (operator)", param);
+
 	if (!r) /* error */
 		return 1;
 	
@@ -117,6 +376,8 @@
 	char * param = get_keyparam(v, MAP);
 	int r = dm_simplecmd(DM_DEVICE_RESUME, param);
 
+	condlog(2, "%s: resume (operator)", param);
+
 	if (!r) /* error */
 		return 1;
 	
@@ -144,6 +405,9 @@
 	if (!pp || !pp->mpp || !pp->mpp->alias)
 		return 1;
 
+	condlog(2, "%s: reinstate path %s (operator)",
+		pp->mpp->alias, pp->dev_t);
+
 	return dm_reinstate_path(pp->mpp->alias, pp->dev_t);
 }
 
@@ -162,5 +426,8 @@
 	if (!pp || !pp->mpp || !pp->mpp->alias)
 		return 1;
 
+	condlog(2, "%s: fail path %s (operator)",
+		pp->mpp->alias, pp->dev_t);
+
 	return dm_fail_path(pp->mpp->alias, pp->dev_t);
 }

Modified: multipath-tools/trunk/multipathd/cli_handlers.h
==============================================================================
--- multipath-tools/trunk/multipathd/cli_handlers.h	(original)
+++ multipath-tools/trunk/multipathd/cli_handlers.h	Mon Mar 13 15:16:41 2006
@@ -1,11 +1,15 @@
 int cli_list_paths (void * v, char ** reply, int * len, void * data);
 int cli_list_maps (void * v, char ** reply, int * len, void * data);
+int cli_list_maps_status (void * v, char ** reply, int * len, void * data);
+int cli_list_maps_stats (void * v, char ** reply, int * len, void * data);
+int cli_list_map_topology (void * v, char ** reply, int * len, void * data);
+int cli_list_maps_topology (void * v, char ** reply, int * len, void * data);
+int cli_list_config (void * v, char ** reply, int * len, void * data);
 int cli_add_path (void * v, char ** reply, int * len, void * data);
 int cli_del_path (void * v, char ** reply, int * len, void * data);
 int cli_add_map (void * v, char ** reply, int * len, void * data);
 int cli_del_map (void * v, char ** reply, int * len, void * data);
 int cli_switch_group(void * v, char ** reply, int * len, void * data);
-int cli_dump_pathvec(void * v, char ** reply, int * len, void * data);
 int cli_reconfigure(void * v, char ** reply, int * len, void * data);
 int cli_suspend(void * v, char ** reply, int * len, void * data);
 int cli_resume(void * v, char ** reply, int * len, void * data);

Modified: multipath-tools/trunk/multipathd/main.c
==============================================================================
--- multipath-tools/trunk/multipathd/main.c	(original)
+++ multipath-tools/trunk/multipathd/main.c	Mon Mar 13 15:16:41 2006
@@ -1,3 +1,9 @@
+/*
+ * Copyright (c) 2004, 2005 Christophe Varoqui
+ * Copyright (c) 2005 Kiyoshi Ueda, NEC
+ * Copyright (c) 2005 Benjamin Marzinski, Redhat
+ * Copyright (c) 2005 Edward Goggin, EMC
+ */
 #include <unistd.h>
 #include <sys/stat.h>
 #include <libdevmapper.h>
@@ -17,7 +23,6 @@
  * libcheckers
  */
 #include <checkers.h>
-#include <path_state.h>
 
 /*
  * libmultipath
@@ -26,12 +31,13 @@
 #include <vector.h>
 #include <memory.h>
 #include <config.h>
-#include <callout.h>
 #include <util.h>
-#include <blacklist.h>
 #include <hwtable.h>
 #include <defaults.h>
 #include <structs.h>
+#include <callout.h>
+#include <blacklist.h>
+#include <structs_vec.h>
 #include <dmparser.h>
 #include <devmapper.h>
 #include <dict.h>
@@ -40,8 +46,8 @@
 #include <propsel.h>
 #include <uevent.h>
 #include <switchgroup.h>
-#include <path_state.h>
 #include <print.h>
+#include <configure.h>
 
 #include "main.h"
 #include "pidfile.h"
@@ -54,10 +60,7 @@
 #define CMDSIZE 160
 
 #define LOG_MSG(a,b) \
-	if (strlen(b)) { \
-		condlog(a, "%s: %s", pp->dev_t, b); \
-		memset(b, 0, MAX_CHECKER_MSG_SIZE); \
-	}
+	if (strlen(b)) condlog(a, "%s: %s", pp->dev_t, b);
 
 #ifdef LCKDBG
 #define lock(a) \
@@ -81,13 +84,7 @@
 /*
  * structs
  */
-struct event_thread {
-	struct dm_task *dmt;
-	pthread_t thread;
-	int event_nr;
-	char mapname[WWID_SIZE];
-	struct vectors *vecs;
-};
+struct vectors * gvecs; /* global copy of vecs for use in sig handlers */
 
 static struct event_thread *
 alloc_waiter (void)
@@ -105,8 +102,24 @@
 {
 	struct event_thread * wp = (struct event_thread *)data;
 
+	/*
+	 * indicate in mpp that the wp is already freed storage
+	 */
+	lock(wp->vecs->lock);
+
+	if (wp->mpp)
+		/*
+		 * be careful, mpp may already be freed -- null if so
+		 */
+		wp->mpp->waiter = NULL;
+	else
+		condlog(3, "free_waiter, mpp freed before wp=%p,", wp);
+
+	unlock(wp->vecs->lock);
+
 	if (wp->dmt)
 		dm_task_destroy(wp->dmt);
+
 	FREE(wp);
 }
 
@@ -114,157 +127,19 @@
 stop_waiter_thread (struct multipath * mpp, struct vectors * vecs)
 {
 	struct event_thread * wp = (struct event_thread *)mpp->waiter;
-	pthread_t thread;
 	
 	if (!wp) {
 		condlog(3, "%s: no waiter thread", mpp->alias);
 		return;
 	}
-	thread = wp->thread;
-
-	if (!wp) {
-		condlog(3, "%s: thread not started", mpp->alias);
-		return;
-	}
 	condlog(2, "%s: stop event checker thread", wp->mapname);
-	pthread_kill(thread, SIGHUP);
+	pthread_kill((pthread_t)wp->thread, SIGUSR1);
 }
 
 static void
 cleanup_lock (void * data)
 {
-	pthread_mutex_unlock((pthread_mutex_t *)data);
-}
-
-static void
-adopt_paths (struct vectors * vecs, struct multipath * mpp)
-{
-	int i;
-	struct path * pp;
-
-	if (!mpp)
-		return;
-
-	vector_foreach_slot (vecs->pathvec, pp, i) {
-		if (!strncmp(mpp->wwid, pp->wwid, WWID_SIZE)) {
-			condlog(4, "%s ownership set", pp->dev_t);
-			pp->mpp = mpp;
-		}
-	}
-}
-
-static void
-orphan_path (struct path * pp)
-{
-	pp->mpp = NULL;
-	pp->checkfn = NULL;
-	pp->dmstate = PSTATE_UNDEF;
-	pp->checker_context = NULL;
-	pp->getuid = NULL;
-	pp->getprio = NULL;
-
-	if (pp->fd >= 0)
-		close(pp->fd);
-
-	pp->fd = -1;
-}
-
-static void
-orphan_paths (struct vectors * vecs, struct multipath * mpp)
-{
-	int i;
-	struct path * pp;
-
-	vector_foreach_slot (vecs->pathvec, pp, i) {
-		if (pp->mpp == mpp) {
-			condlog(4, "%s is orphaned", pp->dev_t);
-			orphan_path(pp);
-		}
-	}
-}
-
-static int
-update_multipath_table (struct multipath *mpp, vector pathvec)
-{
-	if (!mpp)
-		return 1;
-
-	if (dm_get_map(mpp->alias, &mpp->size, mpp->params))
-		return 1;
-
-	if (disassemble_map(pathvec, mpp->params, mpp))
-		return 1;
-
-	return 0;
-}
-
-static int
-update_multipath_status (struct multipath *mpp)
-{
-	if (!mpp)
-		return 1;
-
-	if(dm_get_status(mpp->alias, mpp->status))
-		return 1;
-
-	if (disassemble_status(mpp->status, mpp))
-		return 1;
-
-	return 0;
-}
-
-static int
-update_multipath_strings (struct multipath *mpp, vector pathvec)
-{
-	if (mpp->selector) {
-		FREE(mpp->selector);
-		mpp->selector = NULL;
-	}
-
-	if (mpp->features) {
-		FREE(mpp->features);
-		mpp->features = NULL;
-	}
-
-	if (mpp->hwhandler) {
-		FREE(mpp->hwhandler);
-		mpp->hwhandler = NULL;
-	}
-
-	free_pgvec(mpp->pg, KEEP_PATHS);
-	mpp->pg = NULL;
-
-	if (update_multipath_table(mpp, pathvec))
-		return 1;
-
-	if (update_multipath_status(mpp))
-		return 1;
-
-	return 0;
-}
-
-static void
-set_multipath_wwid (struct multipath * mpp)
-{
-	if (mpp->wwid)
-		return;
-
-	dm_get_uuid(mpp->alias, mpp->wwid);
-}
-
-static int
-pathcount (struct multipath *mpp, int state)
-{
-	struct pathgroup *pgp;
-	struct path *pp;
-	int i, j;
-	int count = 0;
-
-	vector_foreach_slot (mpp->pg, pgp, i)
-		vector_foreach_slot (pgp->paths, pp, j)
-			if (pp->state == state)
-				count++;
-	return count;
+	unlock((pthread_mutex_t *)data);
 }
 
 /*
@@ -283,6 +158,7 @@
 		 * meaning of +1: retry_tick may be decremented in
 		 *                checkerloop before starting retry.
 		 */
+		mpp->stat_queueing_timeouts++;
 		mpp->retry_tick = mpp->no_path_retry * conf->checkint + 1;
 		condlog(1, "%s: Entering recovery mode: max_retries=%d",
 			mpp->alias, mpp->no_path_retry);
@@ -303,111 +179,6 @@
 	condlog(2, "%s: remaining active paths: %d", mpp->alias, mpp->nr_active);
 }
 
-static void
-set_no_path_retry(struct multipath *mpp)
-{
-	mpp->retry_tick = 0;
-	mpp->nr_active = pathcount(mpp, PATH_UP);
-	select_no_path_retry(mpp);
-
-	switch (mpp->no_path_retry) {
-	case NO_PATH_RETRY_UNDEF:
-		break;
-	case NO_PATH_RETRY_FAIL:
-		dm_queue_if_no_path(mpp->alias, 0);
-		break;
-	case NO_PATH_RETRY_QUEUE:
-		dm_queue_if_no_path(mpp->alias, 1);
-		break;
-	default:
-		dm_queue_if_no_path(mpp->alias, 1);
-		if (mpp->nr_active == 0) {
-			/* Enter retry mode */
-			mpp->retry_tick = mpp->no_path_retry * conf->checkint;
-			condlog(1, "%s: Entering recovery mode: max_retries=%d",
-				mpp->alias, mpp->no_path_retry);
-		}
-		break;
-	}
-}
-
-static struct hwentry *
-extract_hwe_from_path(struct multipath * mpp)
-{
-	struct path * pp;
-	struct pathgroup * pgp;
-
-	pgp = VECTOR_SLOT(mpp->pg, 0);
-	pp = VECTOR_SLOT(pgp->paths, 0);
-
-	return pp->hwe;
-}
-
-static void
-remove_map (struct multipath * mpp, struct vectors * vecs)
-{
-	int i;
-
-	stop_waiter_thread(mpp, vecs);
-
-	/*
-	 * clear references to this map
-	 */
-	orphan_paths(vecs, mpp);
-
-	/*
-	 * purge the multipath vector
-	 */
-	i = find_slot(vecs->mpvec, (void *)mpp);
-	vector_del_slot(vecs->mpvec, i);
-
-	/*
-	 * final free
-	 */
-	free_multipath(mpp, KEEP_PATHS);
-	mpp = NULL;
-}
-
-static void
-remove_maps (struct vectors * vecs)
-{
-	int i;
-	struct multipath * mpp;
-
-	vector_foreach_slot (vecs->mpvec, mpp, i) {
-		remove_map(mpp, vecs);
-		i--;
-	}
-
-	vector_free(vecs->mpvec);
-	vecs->mpvec = NULL;
-}
-
-static int
-setup_multipath (struct vectors * vecs, struct multipath * mpp)
-{
-	if (dm_get_info(mpp->alias, &mpp->dmi))
-		goto out;
-
-	set_multipath_wwid(mpp);
-	mpp->mpe = find_mpe(mpp->wwid);
-	condlog(4, "discovered map %s", mpp->alias);
-
-	if (update_multipath_strings(mpp, vecs->pathvec))
-		goto out;
-
-	adopt_paths(vecs, mpp);
-	mpp->hwe = extract_hwe_from_path(mpp);
-	select_pgfailback(mpp);
-	set_no_path_retry(mpp);
-
-	return 0;
-out:
-	condlog(0, "%s: failed to setup multipath", mpp->alias);
-	remove_map(mpp, vecs);
-	return 1;
-}
-
 static int
 need_switch_pathgroup (struct multipath * mpp, int refresh)
 {
@@ -437,12 +208,52 @@
 static void
 switch_pathgroup (struct multipath * mpp)
 {
+	mpp->stat_switchgroup++;
 	dm_switchgroup(mpp->alias, mpp->bestpg);
 	condlog(2, "%s: switch to path group #%i",
 		 mpp->alias, mpp->bestpg);
 }
 
 static int
+coalesce_maps(struct vectors *vecs, vector nmpv)
+{
+	struct multipath * ompp;
+	vector ompv = vecs->mpvec;
+	int i, j;
+
+	vector_foreach_slot (ompv, ompp, i) {
+		if (!find_mp_by_wwid(nmpv, ompp->wwid)) {
+			/*
+			 * remove all current maps not allowed by the
+			 * current configuration
+			 */
+			if (dm_flush_map(ompp->alias, DEFAULT_TARGET)) {
+				condlog(0, "%s: unable to flush devmap",
+					ompp->alias);
+				/*
+				 * may be just because the device is open
+				 */
+				if (!vector_alloc_slot(nmpv))
+					return 1;
+
+				vector_set_slot(nmpv, ompp);
+				setup_multipath(vecs, ompp);
+
+				if ((j = find_slot(ompv, (void *)ompp)) != -1)
+					vector_del_slot(ompv, j);
+
+				continue;
+			}
+			else {
+				dm_lib_release();
+				condlog(3, "%s devmap removed", ompp->alias);
+			}
+		}
+	}
+	return 0;
+}
+
+static int
 update_multipath (struct vectors *vecs, char *mapname)
 {
 	struct multipath *mpp;
@@ -471,9 +282,13 @@
 				continue;
 
 			if (pp->state != PATH_DOWN) {
+				int oldstate = pp->state;
 				condlog(2, "%s: mark as failed", pp->dev_t);
+				mpp->stat_path_failures++;
 				pp->state = PATH_DOWN;
-				update_queue_mode_del_path(mpp);
+				if (oldstate == PATH_UP ||
+				    oldstate == PATH_GHOST)
+					update_queue_mode_del_path(mpp);
 
 				/*
 				 * if opportune,
@@ -492,12 +307,13 @@
 	return r;
 }
 
-static sigset_t unblock_sighup(void)
+static sigset_t unblock_signals(void)
 {
 	sigset_t set, old;
 
 	sigemptyset(&set);
 	sigaddset(&set, SIGHUP);
+	sigaddset(&set, SIGUSR1);
 	pthread_sigmask(SIG_UNBLOCK, &set, &old);
 	return old;
 }
@@ -516,16 +332,23 @@
 	if (!waiter->event_nr)
 		waiter->event_nr = dm_geteventnr(waiter->mapname);
 
-	if (!(waiter->dmt = dm_task_create(DM_DEVICE_WAITEVENT)))
+	if (!(waiter->dmt = dm_task_create(DM_DEVICE_WAITEVENT))) {
+		condlog(0, "%s: devmap event #%i dm_task_create error",
+				waiter->mapname, waiter->event_nr);
 		return 1;
+	}
 
 	if (!dm_task_set_name(waiter->dmt, waiter->mapname)) {
+		condlog(0, "%s: devmap event #%i dm_task_set_name error",
+				waiter->mapname, waiter->event_nr);
 		dm_task_destroy(waiter->dmt);
 		return 1;
 	}
 
 	if (waiter->event_nr && !dm_task_set_event_nr(waiter->dmt,
 						      waiter->event_nr)) {
+		condlog(0, "%s: devmap event #%i dm_task_set_event_nr error",
+				waiter->mapname, waiter->event_nr);
 		dm_task_destroy(waiter->dmt);
 		return 1;
 	}
@@ -533,7 +356,7 @@
 	dm_task_no_open_count(waiter->dmt);
 	
 	/* accept wait interruption */
-	set = unblock_sighup();
+	set = unblock_signals();
 
 	/* interruption spits messages */
 	dm_shut_log();
@@ -635,6 +458,7 @@
 	mpp->waiter = (void *)wp;
 	strncpy(wp->mapname, mpp->alias, WWID_SIZE);
 	wp->vecs = vecs;
+	wp->mpp = mpp;
 
 	if (pthread_create(&wp->thread, &attr, waitevent, wp)) {
 		condlog(0, "%s: cannot create event checker", wp->mapname);
@@ -651,13 +475,83 @@
 	return 1;
 }
 
-int
+static void
+sync_map_state(struct multipath *mpp)
+{
+	int i, j;
+	struct pathgroup *pgp;
+        struct path *pp;
+
+	vector_foreach_slot (mpp->pg, pgp, i){
+		vector_foreach_slot (pgp->paths, pp, j){
+			if (pp->state <= PATH_UNCHECKED)
+				continue;
+			if ((pp->dmstate == PSTATE_FAILED ||
+			     pp->dmstate == PSTATE_UNDEF) &&
+			    (pp->state == PATH_UP || pp->state == PATH_GHOST))
+				dm_reinstate_path(mpp->alias, pp->dev_t);
+			else if ((pp->dmstate == PSTATE_ACTIVE ||
+				  pp->dmstate == PSTATE_UNDEF) &&
+				 (pp->state == PATH_DOWN ||
+				  pp->state == PATH_SHAKY))
+				dm_fail_path(mpp->alias, pp->dev_t);
+		}
+	}
+}
+
+static void
+sync_maps_state(vector mpvec)
+{
+	int i;
+	struct multipath *mpp;
+
+	vector_foreach_slot (mpvec, mpp, i) 
+		sync_map_state(mpp);
+}
+
+static int
+flush_map(struct multipath * mpp, struct vectors * vecs)
+{
+	/*
+	 * clear references to this map before flushing so we can ignore
+	 * the spurious uevent we may generate with the dm_flush_map call below
+	 */
+	if (dm_flush_map(mpp->alias, DEFAULT_TARGET)) {
+		/*
+		 * May not really be an error -- if the map was already flushed
+		 * from the device mapper by dmsetup(8) for instance.
+		 */
+		condlog(0, "%s: can't flush", mpp->alias);
+		return 1;
+	}
+	else {
+		dm_lib_release();
+		condlog(3, "%s: devmap removed", mpp->alias);
+	}
+
+	orphan_paths(vecs->pathvec, mpp);
+	remove_map(mpp, vecs, stop_waiter_thread, 1);
+
+	return 0;
+}
+
+static int
 uev_add_map (char * devname, struct vectors * vecs)
 {
+	condlog(2, "%s: add map (uevent)", devname);
+	return ev_add_map(devname, vecs);
+}
+
+int
+ev_add_map (char * devname, struct vectors * vecs)
+{
 	int major, minor;
 	char dev_t[BLK_DEV_SIZE];
 	char * alias;
+	char * refwwid;
 	struct multipath * mpp;
+	int map_present;
+	int r = 1;
 
 	if (sscanf(devname, "dm-%d", &minor) == 1 &&
 	    !sysfs_get_dev(sysfs_path, devname, dev_t, BLK_DEV_SIZE) &&
@@ -669,7 +563,9 @@
 	if (!alias)
 		return 1;
 	
-	if (!dm_type(alias, DEFAULT_TARGET)) {
+	map_present = dm_map_present(alias);
+
+	if (map_present && dm_type(alias, DEFAULT_TARGET) <= 0) {
 		condlog(4, "%s: not a multipath map", alias);
 		FREE(alias);
 		return 0;
@@ -678,206 +574,325 @@
 	mpp = find_mp_by_alias(vecs->mpvec, alias);
 
 	if (mpp) {
-		/*
-		 * this should not happen,
-		 * we missed a remove map event (not sent ?)
+                /*
+		 * Not really an error -- we generate our own uevent
+		 * if we create a multipath mapped device as a result
+		 * of uev_add_path
 		 */
-		condlog(2, "%s: already registered", alias);
-		remove_map(mpp, vecs);
+		condlog(0, "%s: devmap already registered",
+			devname);
+		FREE(alias);
+		return 0;
 	}
 
 	/*
-	 * now we can allocate
+	 * now we can register the map
 	 */
-	mpp = alloc_multipath();
-
-	if (!mpp)
-		return 1;
-
-	mpp->alias = alias;
-
-	if (setup_multipath(vecs, mpp))
-		return 1; /* mpp freed in setup_multipath */
-
-	if (!vector_alloc_slot(vecs->mpvec))
-		goto out;
+	if (map_present && (mpp = add_map_without_path(vecs, minor, alias,
+					start_waiter_thread))) {
+		sync_map_state(mpp);
+		condlog(3, "%s: devmap %s added", alias, devname);
+		return 0;
+	}
+	refwwid = get_refwwid(devname, DEV_DEVMAP, vecs->pathvec);
 
-	vector_set_slot(vecs->mpvec, mpp);
-	adopt_paths(vecs, mpp);
+	if (refwwid) {
+		r = coalesce_paths(vecs, NULL, refwwid);
+		dm_lib_release();
+	}
+	
+	if (!r)
+		condlog(3, "%s: devmap %s added", alias, devname);
+	else
+		condlog(0, "%s: uev_add_map %s failed", alias, devname);
 
-	if (start_waiter_thread(mpp, vecs))
-		goto out;
+	FREE(refwwid);
+	FREE(alias);
+	return r;
+}
 
-	return 0;
-out:
-	condlog(2, "%s: add devmap failed", mpp->alias);
-	remove_map(mpp, vecs);
-	return 1;
+static int
+uev_remove_map (char * devname, struct vectors * vecs)
+{
+	condlog(2, "%s: remove map (uevent)", devname);
+	return ev_remove_map(devname, vecs);
 }
 
 int
-uev_remove_map (char * devname, struct vectors * vecs)
+ev_remove_map (char * devname, struct vectors * vecs)
 {
-	int minor;
 	struct multipath * mpp;
 
-	if (sscanf(devname, "dm-%d", &minor) == 1)
-		mpp = find_mp_by_minor(vecs->mpvec, minor);
-	else
-		mpp = find_mp_by_alias(vecs->mpvec, devname);
+	mpp = find_mp_by_str(vecs->mpvec, devname);
 
 	if (!mpp) {
 		condlog(3, "%s: devmap not registered, can't remove",
 			devname);
 		return 0;
 	}
-
-	condlog(2, "remove %s devmap", mpp->alias);
-	remove_map(mpp, vecs);
+	flush_map(mpp, vecs);
 
 	return 0;
 }
 
-int
-uev_add_path (char * devname, struct vectors * vecs)
+static int
+uev_umount_map (char * devname, struct vectors * vecs)
 {
-	struct path * pp;
+	struct multipath * mpp;
 
-	pp = find_path_by_dev(vecs->pathvec, devname);
+	condlog(2, "%s: umount map (uevent)", devname);
 
-	if (pp) {
-		condlog(3, "%s: already in pathvec");
-		return 1;
-	}
-	pp = store_pathinfo(vecs->pathvec, conf->hwtable,
-		       devname, DI_SYSFS | DI_WWID);
+	mpp = find_mp_by_str(vecs->mpvec, devname);
 
-	if (!pp) {
-		condlog(0, "%s: failed to store path info", devname);
-		return 1;
-	}
+	if (!mpp)
+		return 0;
 
-	condlog(2, "%s: path checker registered", devname);
-	pp->mpp = find_mp_by_wwid(vecs->mpvec, pp->wwid);
+	update_mpp_paths(mpp, vecs->pathvec);
+	verify_paths(mpp, vecs, NULL);
 
-	if (pp->mpp) {
-		condlog(4, "%s: ownership set to %s",
-				pp->dev_t, pp->mpp->alias);
-	} else {
-		condlog(4, "%s: orphaned", pp->dev_t);
-		orphan_path(pp);
-	}
+	if (!VECTOR_SIZE(mpp->paths))
+		flush_map(mpp, vecs);
 
 	return 0;
 }
+	
+static int
+uev_add_path (char * devname, struct vectors * vecs)
+{
+	condlog(2, "%s: add path (uevent)", devname);
+	return (ev_add_path(devname, vecs) != 1)? 0 : 1;
+}
+
 
+/*
+ * returns:
+ * 0: added
+ * 1: error
+ * 2: blacklisted
+ */
 int
-uev_remove_path (char * devname, struct vectors * vecs)
+ev_add_path (char * devname, struct vectors * vecs)
 {
-	int i;
+	struct multipath * mpp;
 	struct path * pp;
+	char empty_buff[WWID_SIZE] = {0};
 
 	pp = find_path_by_dev(vecs->pathvec, devname);
 
-	if (!pp) {
-		condlog(3, "%s: not in pathvec");
-		return 1;
+	if (pp) {
+		condlog(0, "%s: spurious uevent, path already in pathvec",
+			devname);
+		if (pp->mpp)
+			return 0;
+	}
+	else {
+		/*
+		 * get path vital state
+		 */
+		if (!(pp = store_pathinfo(vecs->pathvec, conf->hwtable,
+		      devname, DI_ALL))) {
+			condlog(0, "%s: failed to store path info", devname);
+			return 1;
+		}
+		pp->checkint = conf->checkint;
 	}
 
-	if (pp->mpp && pp->state == PATH_UP)
-		update_queue_mode_del_path(pp->mpp);
+	/*
+	 * need path UID to go any further
+	 */
+	if (memcmp(empty_buff, pp->wwid, WWID_SIZE) == 0) {
+		condlog(0, "%s: failed to get path uid", devname);
+		return 1; /* leave path added to pathvec */
+	}
+	if (blacklist_path(conf, pp)){
+		int i = find_slot(vecs->pathvec, (void *)pp);
+		if (i != -1)
+			vector_del_slot(vecs->pathvec, i);
+		free_path(pp);
+		return 2;
+	}	
+	mpp = pp->mpp = find_mp_by_wwid(vecs->mpvec, pp->wwid);
+rescan:
+	if (mpp) {
+		if (adopt_paths(vecs->pathvec, mpp))
+			return 1; /* leave path added to pathvec */
 
-	condlog(2, "remove %s path checker", devname);
-	i = find_slot(vecs->pathvec, (void *)pp);
-	vector_del_slot(vecs->pathvec, i);
-	free_path(pp);
+		verify_paths(mpp, vecs, NULL);
+		mpp->action = ACT_RELOAD;
+	}
+	else {
+		if ((mpp = add_map_with_path(vecs, pp, 1)))
+			mpp->action = ACT_CREATE;
+		else
+			return 1; /* leave path added to pathvec */
+	}
 
-	return 0;
-}
+	/*
+	 * push the map to the device-mapper
+	 */
+	if (setup_map(mpp)) {
+		condlog(0, "%s: failed to setup map for addition of new "
+			"path %s", mpp->alias, devname);
+		goto out;
+	}
+	/*
+	 * reload the map for the multipath mapped device
+	 */
+	if (domap(mpp) <= 0) {
+		condlog(0, "%s: failed in domap for addition of new "
+			"path %s", mpp->alias, devname);
+		/*
+ 		 * deal with asynchronous uevents :((
+ 		 */
+		if (mpp->action == ACT_RELOAD) {
+			condlog(0, "%s: uev_add_path sleep", mpp->alias);
+			sleep(1);
+			update_mpp_paths(mpp, vecs->pathvec);
+			goto rescan;
+		}
+		else
+			goto out;
+	}
+	dm_lib_release();
 
-int
-show_paths (char ** r, int * len, struct vectors * vecs)
-{
-	int i;
-	struct path * pp;
-	char * c;
-	char * reply;
-	struct path_layout pl;
+	/*
+	 * update our state from kernel regardless of create or reload
+	 */
+	if (setup_multipath(vecs, mpp))
+		goto out;
 
-	get_path_layout(&pl, vecs->pathvec);
-	reply = MALLOC(MAX_REPLY_LEN);
+	sync_map_state(mpp);
 
-	if (!reply)
-		return 1;
+	if (mpp->action == ACT_CREATE &&
+	    start_waiter_thread(mpp, vecs))
+			goto out;
 
-	c = reply;
+	condlog(3, "%s path added to devmap %s", devname, mpp->alias);
+	return 0;
 
-	if (VECTOR_SIZE(vecs->pathvec) > 0)
-		c += snprint_path_header(c, reply + MAX_REPLY_LEN - c,
-					 PRINT_PATH_CHECKER, &pl);
-
-	vector_foreach_slot(vecs->pathvec, pp, i)
-		c += snprint_path(c, reply + MAX_REPLY_LEN - c,
-			       	  PRINT_PATH_CHECKER, pp, &pl);
+out:
+	remove_map(mpp, vecs, NULL, 1);
+	return 1;
+}
 
-	*r = reply;
-	*len = (int)(c - reply + 1);
-	return 0;
+static int
+uev_remove_path (char * devname, struct vectors * vecs)
+{
+	condlog(2, "%s: remove path (uevent)", devname);
+	return ev_remove_path(devname, vecs);
 }
 
 int
-show_maps (char ** r, int *len, struct vectors * vecs)
+ev_remove_path (char * devname, struct vectors * vecs)
 {
-	int i;
 	struct multipath * mpp;
-	char * c;
-	char * reply;
-	struct map_layout ml;
+	struct path * pp;
+	int i;
+	int rm_path = 1;
 
-	get_map_layout(&ml, vecs->mpvec);
-	reply = MALLOC(MAX_REPLY_LEN);
+	pp = find_path_by_dev(vecs->pathvec, devname);
 
-	if (!reply)
+	if (!pp) {
+		condlog(0, "%s: spurious uevent, path not in pathvec", devname);
 		return 1;
+	}
 
-	c = reply;
-	if (VECTOR_SIZE(vecs->mpvec) > 0)
-		c += snprint_map_header(c, reply + MAX_REPLY_LEN - c,
-					PRINT_MAP_FAILBACK, &ml);
-
-	vector_foreach_slot(vecs->mpvec, mpp, i)
-		c += snprint_map(c, reply + MAX_REPLY_LEN - c,
-			       	 PRINT_MAP_FAILBACK, mpp, &ml);
+	/*
+	 * avoid referring to the map of an orphanned path
+	 */
+	if ((mpp = pp->mpp)) {
 
-	*r = reply;
-	*len = (int)(c - reply + 1);
-	return 0;
-}
+		/*
+		 * remove the map IFF removing the last path
+		 */
+		if (pathcount(mpp, PATH_WILD) > 1) {
+			vector rpvec = vector_alloc();
 
-int
-dump_pathvec (char ** r, int * len, struct vectors * vecs)
-{
-	int i;
-	struct path * pp;
-	char * reply;
-	char * p;
+			/*
+	 	 	 * transform the mp->pg vector of vectors of paths
+	 	 	 * into a mp->params string to feed the device-mapper
+	 	 	 */
+			update_mpp_paths(mpp, vecs->pathvec);
+			if ((i = find_slot(mpp->paths, (void *)pp)) != -1)
+				vector_del_slot(mpp->paths, i);
 
-	*len = VECTOR_SIZE(vecs->pathvec) * sizeof(struct path);
-	reply = (char *)MALLOC(*len);
-	*r = reply;
+			if (VECTOR_SIZE(mpp->paths) == 0) {
+				char alias[WWID_SIZE];
 
-	if (!reply)
-		return 1;
+				/*
+				 * flush_map will fail if the device is open
+				 */
+				strncpy(alias, mpp->alias, WWID_SIZE);
+				if (flush_map(mpp, vecs))
+					rm_path = 0;
+				else
+					condlog(3, "%s: removed map after removing"
+						" multiple paths", alias);
+			}
+			else {
+				if (setup_map(mpp)) {
+					condlog(0, "%s: failed to setup map for"
+						" removal of path %s", mpp->alias, devname);
+					free_pathvec(rpvec, KEEP_PATHS);
+					goto out;
+				}
+				/*
+	 	 	 	 * reload the map
+	 	 	 	 */
+				mpp->action = ACT_RELOAD;
+				if (domap(mpp) <= 0) {
+					condlog(0, "%s: failed in domap for "
+						"removal of path %s",
+						mpp->alias, devname);
+					/*
+					 * Delete path from pathvec so that
+					 * update_mpp_paths wont find it later
+					 * when/if another path is removed.
+					 */
+					if ((i = find_slot(vecs->pathvec, (void *)pp)) != -1)
+						vector_del_slot(vecs->pathvec, i);
+					free_path(pp);
+					return 1;
+				}
+				/*
+				 * update our state from kernel
+				 */
+				if (setup_multipath(vecs, mpp)) {
+					free_pathvec(rpvec, KEEP_PATHS);
+					goto out;
+				}
+				sync_map_state(mpp);
 
-	p = reply;
+				condlog(3, "%s path removed from devmap %s",
+					devname, mpp->alias);
+			}
+			free_pathvec(rpvec, KEEP_PATHS);
+		}
+		else {
+			char alias[WWID_SIZE];
 
-	vector_foreach_slot (vecs->pathvec, pp, i) {
-		memcpy((void *)p, pp, sizeof(struct path));
-		p += sizeof(struct path);
+			/*
+			 * flush_map will fail if the device is open
+			 */
+			strncpy(alias, mpp->alias, WWID_SIZE);
+			if (flush_map(mpp, vecs))
+				rm_path = 0;
+			else
+				condlog(3, "%s: removed map", alias);
+		}
+	}
+
+	if (rm_path) {
+		if ((i = find_slot(vecs->pathvec, (void *)pp)) != -1)
+			vector_del_slot(vecs->pathvec, i);
+		free_path(pp);
 	}
 
-	/* return negative to hint caller not to add "ok" to the dump */
-	return -1;
+	return 0;
+
+out:
+	remove_map(mpp, vecs, stop_waiter_thread, 1);
+	return 1;
 }
 
 static int
@@ -889,49 +904,14 @@
 	if (dm_get_maps(vecs->mpvec, "multipath"))
 		return 1;
 
-	vector_foreach_slot (vecs->mpvec, mpp, i) {
+	vector_foreach_slot (vecs->mpvec, mpp, i)
 		if (setup_multipath(vecs, mpp))
 			return 1;
-		start_waiter_thread(mpp, vecs);
-	}
 
 	return 0;
 }
 
 int
-reconfigure (struct vectors * vecs)
-{
-	struct config * old = conf;
-	struct multipath * mpp;
-	struct path * pp;
-	int i;
-
-	conf = NULL;
-
-	if (load_config(DEFAULT_CONFIGFILE)) {
-		conf = old;
-		condlog(2, "reconfigure failed, continue with old config");
-		return 1;
-	}
-	conf->verbosity = old->verbosity;
-	free_config(old);
-
-	vector_foreach_slot (vecs->mpvec, mpp, i) {
-		mpp->mpe = find_mpe(mpp->wwid);
-		mpp->hwe = extract_hwe_from_path(mpp);
-		adopt_paths(vecs, mpp);
-		set_no_path_retry(mpp);
-	}
-	vector_foreach_slot (vecs->pathvec, pp, i) {
-		select_checkfn(pp);
-		select_getuid(pp);
-		select_getprio(pp);
-	}
-	condlog(2, "reconfigured");
-	return 0;
-}
-
-int
 uxsock_trigger (char * str, char ** reply, int * len, void * trigger_data)
 {
 	struct vectors * vecs;
@@ -988,7 +968,7 @@
 	vecs = (struct vectors *)trigger_data;
 
 	if (uev_discard(uev->devpath))
-		goto out;
+		return 0;
 
 	basename(uev->devpath, devname);
 	lock(vecs->lock);
@@ -1001,19 +981,21 @@
 			r = uev_add_map(devname, vecs);
 			goto out;
 		}
-#if 0
 		if (!strncmp(uev->action, "remove", 6)) {
 			r = uev_remove_map(devname, vecs);
 			goto out;
 		}
-#endif
+		if (!strncmp(uev->action, "umount", 6)) {
+			r = uev_umount_map(devname, vecs);
+			goto out;
+		}
 		goto out;
 	}
 	
 	/*
 	 * path add/remove event
 	 */
-	if (blacklist(conf->blist, devname))
+	if (blacklist(conf->blist_devnode, devname))
 		goto out;
 
 	if (!strncmp(uev->action, "add", 3)) {
@@ -1050,12 +1032,17 @@
 
 	add_handler(LIST+PATHS, cli_list_paths);
 	add_handler(LIST+MAPS, cli_list_maps);
+	add_handler(LIST+MAPS+STATUS, cli_list_maps_status);
+	add_handler(LIST+MAPS+STATS, cli_list_maps_stats);
+	add_handler(LIST+MAPS+TOPOLOGY, cli_list_maps_topology);
+	add_handler(LIST+TOPOLOGY, cli_list_maps_topology);
+	add_handler(LIST+MAP+TOPOLOGY, cli_list_map_topology);
+	add_handler(LIST+CONFIG, cli_list_config);
 	add_handler(ADD+PATH, cli_add_path);
 	add_handler(DEL+PATH, cli_del_path);
 	add_handler(ADD+MAP, cli_add_map);
 	add_handler(DEL+MAP, cli_del_map);
 	add_handler(SWITCH+MAP+GROUP, cli_switch_group);
-	add_handler(DUMP+PATHVEC, cli_dump_pathvec);
 	add_handler(RECONFIGURE, cli_reconfigure);
 	add_handler(SUSPEND+MAP, cli_suspend);
 	add_handler(RESUME+MAP, cli_resume);
@@ -1084,7 +1071,7 @@
 }
 
 static void
-fail_path (struct path * pp)
+fail_path (struct path * pp, int del_active)
 {
 	if (!pp->mpp)
 		return;
@@ -1093,14 +1080,15 @@
 		 pp->dev_t, pp->mpp->alias);
 
 	dm_fail_path(pp->mpp->alias, pp->dev_t);
-	update_queue_mode_del_path(pp->mpp);
+	if (del_active)
+		update_queue_mode_del_path(pp->mpp);
 }
 
 /*
  * caller must have locked the path list before calling that function
  */
 static void
-reinstate_path (struct path * pp)
+reinstate_path (struct path * pp, int add_active)
 {
 	if (!pp->mpp)
 		return;
@@ -1109,7 +1097,8 @@
 		condlog(0, "%s: reinstate failed", pp->dev_t);
 	else {
 		condlog(2, "%s: reinstated", pp->dev_t);
-		update_queue_mode_add_path(pp->mpp);
+		if (add_active)
+			update_queue_mode_add_path(pp->mpp);
 	}
 }
 
@@ -1125,7 +1114,7 @@
 	 * we can safely return here, because upon map reload, all
 	 * PG will be enabled.
  	 */
-	if (!pp->pgindex)
+	if (!pp->mpp->pg || !pp->pgindex)
 		return;
 
 	pgp = VECTOR_SLOT(pp->mpp->pg, pp->pgindex - 1);
@@ -1145,7 +1134,7 @@
 	vector_foreach_slot (vecs->mpvec, mpp, i) {
 		if (mpp && mpp->alias && !dm_map_present(mpp->alias)) {
 			condlog(2, "%s: remove dead map", mpp->alias);
-			remove_map(mpp, vecs);
+			remove_map(mpp, vecs, stop_waiter_thread, 1);
 			i--;
 		}
 	}
@@ -1178,6 +1167,7 @@
 
 	vector_foreach_slot (mpvec, mpp, i) {
 		if (mpp->retry_tick) {
+			mpp->stat_total_queueing_time++;
 			condlog(4, "%s: Retrying.. No active path", mpp->alias);
 			if(--mpp->retry_tick == 0) {
 				dm_queue_if_no_path(mpp->alias, 0);
@@ -1194,13 +1184,9 @@
 	struct path *pp;
 	int i, count = 0;
 	int newstate;
-	char checker_msg[MAX_CHECKER_MSG_SIZE];
 
 	mlockall(MCL_CURRENT | MCL_FUTURE);
-
-	memset(checker_msg, 0, MAX_CHECKER_MSG_SIZE);
 	vecs = (struct vectors *)ap;
-
 	condlog(2, "path checkers start up");
 
 	/*
@@ -1228,21 +1214,27 @@
 			 */
 			pp->tick = conf->checkint;
 			
-			if (!pp->checkfn) {
+			if (!checker_selected(&pp->checker)) {
 				pathinfo(pp, conf->hwtable, DI_SYSFS);
-				select_checkfn(pp);
+				select_checker(pp);
 			}
 
-			if (!pp->checkfn) {
-				condlog(0, "%s: checkfn is void", pp->dev);
+			if (!checker_selected(&pp->checker)) {
+				condlog(0, "%s: checker is not set", pp->dev);
 				continue;
 			}
-			newstate = pp->checkfn(pp->fd, checker_msg,
-					       &pp->checker_context);
+			newstate = checker_check(&pp->checker);
 			
+			if (newstate < 0) {
+				condlog(2, "%s: unusable path", pp->dev);
+				pathinfo(pp, conf->hwtable, 0);
+				continue;
+			}
+
 			if (newstate != pp->state) {
+				int oldstate = pp->state;
 				pp->state = newstate;
-				LOG_MSG(1, checker_msg);
+				LOG_MSG(1, checker_message(&pp->checker));
 
 				/*
 				 * upon state change, reset the checkint
@@ -1251,33 +1243,38 @@
 				pp->checkint = conf->checkint;
 
 				if (newstate == PATH_DOWN ||
-				    newstate == PATH_SHAKY) {
+				    newstate == PATH_SHAKY ||
+				    update_multipath_strings(pp->mpp,
+					    		     vecs->pathvec)) {
 					/*
 					 * proactively fail path in the DM
 					 */
-					fail_path(pp);
+					if (oldstate == PATH_UP ||
+					    oldstate == PATH_GHOST)
+						fail_path(pp, 1);
+					else
+						fail_path(pp, 0);
 
 					/*
 					 * cancel scheduled failback
 					 */
 					pp->mpp->failback_tick = 0;
 
+					pp->mpp->stat_path_failures++;
 					continue;
 				}
 
 				/*
 				 * reinstate this path
 				 */
-				reinstate_path(pp);
-
-				/*
-				 * need to switch group ?
-				 */
-				update_multipath_strings(pp->mpp,
-							 vecs->pathvec);
+				if (oldstate != PATH_UP &&
+				    oldstate != PATH_GHOST)
+					reinstate_path(pp, 1);
+				else
+					reinstate_path(pp, 0);
 
 				/*
-				 * schedule defered failback
+				 * schedule [defered] failback
 				 */
 				if (pp->mpp->pgfailback > 0)
 					pp->mpp->failback_tick =
@@ -1294,7 +1291,7 @@
 					enable_group(pp);
 			}
 			else if (newstate == PATH_UP || newstate == PATH_GHOST) {
-				LOG_MSG(4, checker_msg);
+				LOG_MSG(4, checker_message(&pp->checker));
 				/*
 				 * double the next check delay.
 				 * max at conf->max_checkint
@@ -1307,8 +1304,10 @@
 				pp->tick = pp->checkint;
 				condlog(4, "%s: delay next check %is",
 						pp->dev_t, pp->tick);
-
 			}
+			else if (newstate == PATH_DOWN)
+				LOG_MSG(2, checker_message(&pp->checker));
+
 			pp->state = newstate;
 
 			/*
@@ -1318,7 +1317,8 @@
 			pathinfo(pp, conf->hwtable, DI_PRIO);
 
 			if (need_switch_pathgroup(pp->mpp, 0)) {
-				if (pp->mpp->pgfailback > 0)
+				if (pp->mpp->pgfailback > 0 &&
+				    pp->mpp->failback_tick <= 0)
 					pp->mpp->failback_tick =
 						pp->mpp->pgfailback + 1;
 				else if (pp->mpp->pgfailback ==
@@ -1343,8 +1343,116 @@
 	return NULL;
 }
 
+int
+configure (struct vectors * vecs, int start_waiters)
+{
+	struct multipath * mpp;
+	struct path * pp;
+	vector mpvec;
+	int i;
+
+	if (!(vecs->pathvec = vector_alloc()))
+		return 1;
+	
+	if (!(vecs->mpvec = vector_alloc()))
+		return 1;
+	
+	if (!(mpvec = vector_alloc()))
+		return 1;
+
+	/*
+	 * probe for current path (from sysfs) and map (from dm) sets
+	 */
+	path_discovery(vecs->pathvec, conf, DI_ALL);
+
+	vector_foreach_slot (vecs->pathvec, pp, i){
+		if (blacklist_path(conf, pp)){
+			vector_del_slot(vecs->pathvec, i);
+			free_path(pp);
+			i--;
+		}	
+		else
+			pp->checkint = conf->checkint;
+	}
+	if (map_discovery(vecs))
+		return 1;
+
+	/*
+	 * create new set of maps & push changed ones into dm
+	 */
+	if (coalesce_paths(vecs, mpvec, NULL))
+		return 1;
+
+	/*
+	 * may need to remove some maps which are no longer relevant
+	 * e.g., due to blacklist changes in conf file
+	 */
+	if (coalesce_maps(vecs, mpvec))
+		return 1;
+
+	dm_lib_release();
+
+	sync_maps_state(mpvec);
+
+	if (conf->verbosity > 2)
+		vector_foreach_slot(mpvec, mpp, i)
+			print_map(mpp);
+
+	/*
+	 * purge dm of old maps
+	 */
+	remove_maps(vecs, NULL);
+
+	/*
+	 * save new set of maps formed by considering current path state
+	 */
+	vecs->mpvec = mpvec;
+
+	/*
+	 * start dm event waiter threads for these new maps
+	 */
+	vector_foreach_slot(vecs->mpvec, mpp, i) {
+		if (setup_multipath(vecs, mpp))
+			return 1;
+		if (start_waiters)
+			if (start_waiter_thread(mpp, vecs))
+				return 1;
+	}
+	return 0;
+}
+
+int
+reconfigure (struct vectors * vecs)
+{
+	struct config * old = conf;
+
+	/*
+	 * free old map and path vectors ... they use old conf state
+	 */
+	if (VECTOR_SIZE(vecs->mpvec))
+		remove_maps(vecs, stop_waiter_thread);
+
+	if (VECTOR_SIZE(vecs->pathvec))
+		free_pathvec(vecs->pathvec, FREE_PATHS);
+
+	conf = NULL;
+
+	if (load_config(DEFAULT_CONFIGFILE))
+		return 1;
+
+	conf->verbosity = old->verbosity;
+
+	if (!conf->checkint) {
+		conf->checkint = DEFAULT_CHECKINT;
+		conf->max_checkint = MAX_CHECKINT(conf->checkint);
+	}
+	configure(vecs, 1);
+	free_config(old);
+	return 0;
+}
+
 static struct vectors *
-init_paths (void)
+init_vecs (void)
 {
 	struct vectors * vecs;
 
@@ -1405,7 +1513,11 @@
 static void
 sighup (int sig)
 {
-	condlog(3, "SIGHUP received");
+	condlog(2, "reconfigure (SIGHUP)");
+
+	lock(gvecs->lock);
+	reconfigure(gvecs);
+	unlock(gvecs->lock);
 
 #ifdef _DEBUG_
 	dbg_free_final(NULL);
@@ -1419,9 +1531,16 @@
 }
 
 static void
+sigusr1 (int sig)
+{
+	condlog(3, "SIGUSR1 received");
+}
+
+static void
 signal_init(void)
 {
 	signal_set(SIGHUP, sighup);
+	signal_set(SIGUSR1, sigusr1);
 	signal_set(SIGINT, sigend);
 	signal_set(SIGTERM, sigend);
 	signal_set(SIGKILL, sigend);
@@ -1480,8 +1599,8 @@
 	 * fill the voids left in the config file
 	 */
 	if (!conf->checkint) {
-		conf->checkint = CHECKINT;
-		conf->max_checkint = MAX_CHECKINT;
+		conf->checkint = DEFAULT_CHECKINT;
+		conf->max_checkint = MAX_CHECKINT(conf->checkint);
 	}
 
 	if (pidfile_create(DEFAULT_PIDFILE, getpid())) {
@@ -1492,8 +1611,8 @@
 	}
 	signal_init();
 	setscheduler();
-	set_oom_adj(-17);
-	vecs = init_paths();
+	set_oom_adj(-16);
+	vecs = gvecs = init_vecs();
 
 	if (!vecs)
 		exit(1);
@@ -1504,12 +1623,12 @@
 	}
 
 	/*
-	 * fetch paths and multipaths lists
-	 * no paths and/or no multipaths are valid scenarii
-	 * vectors maintenance will be driven by events
+	 * fetch and configure both paths and multipaths
 	 */
-	path_discovery(vecs->pathvec, conf, DI_SYSFS | DI_WWID | DI_CHECKER);
-	map_discovery(vecs);
+	if (configure(vecs, 1)) {
+		condlog(0, "failure during configuration");
+		exit(1);
+	}
 
 	/*
 	 * start threads
@@ -1528,7 +1647,7 @@
 	 * exit path
 	 */
 	lock(vecs->lock);
-	remove_maps(vecs);
+	remove_maps(vecs, stop_waiter_thread);
 	free_pathvec(vecs->pathvec, FREE_PATHS);
 
 	pthread_cancel(check_thr);
@@ -1555,6 +1674,9 @@
 	if (logsink)
 		log_thread_stop();
 
+	dm_lib_release();
+	dm_lib_exit();
+
 #ifdef _DEBUG_
 	dbg_free_final(NULL);
 #endif
@@ -1669,3 +1791,4 @@
 		/* child lives */
 		return (child(NULL));
 }
+

Modified: multipath-tools/trunk/multipathd/main.h
==============================================================================
--- multipath-tools/trunk/multipathd/main.h	(original)
+++ multipath-tools/trunk/multipathd/main.h	Mon Mar 13 15:16:41 2006
@@ -2,23 +2,12 @@
 #define MAIN_H
 
 #define DAEMON 1
-#define CHECKINT 5
 #define MAPGCINT 5
-#define MAX_CHECKINT CHECKINT << 2
-
-struct vectors {
-	pthread_mutex_t *lock;
-	vector pathvec;
-	vector mpvec;
-};
 
 int reconfigure (struct vectors *);
-int show_paths (char **, int *, struct vectors *);
-int show_maps (char **, int *, struct vectors *);
-int dump_pathvec (char **, int *, struct vectors *);
-int uev_add_path (char *, struct vectors *);
-int uev_remove_path (char *, struct vectors *);
-int uev_add_map (char *, struct vectors *);
-int uev_remove_map (char *, struct vectors *);
+int ev_add_path (char *, struct vectors *);
+int ev_remove_path (char *, struct vectors *);
+int ev_add_map (char *, struct vectors *);
+int ev_remove_map (char *, struct vectors *);
 
 #endif /* MAIN_H */

Modified: multipath-tools/trunk/multipathd/uxclnt.c
==============================================================================
--- multipath-tools/trunk/multipathd/uxclnt.c	(original)
+++ multipath-tools/trunk/multipathd/uxclnt.c	Mon Mar 13 15:16:41 2006
@@ -1,3 +1,9 @@
+/*
+ * Original author : tridge at samba.org, January 2002
+ * 
+ * Copyright (c) 2005 Christophe Varoqui
+ * Copyright (c) 2005 Benjamin Marzinski, Redhat
+ */
 #include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>

Modified: multipath-tools/trunk/multipathd/uxlsnr.c
==============================================================================
--- multipath-tools/trunk/multipathd/uxlsnr.c	(original)
+++ multipath-tools/trunk/multipathd/uxlsnr.c	Mon Mar 13 15:16:41 2006
@@ -1,6 +1,12 @@
 /*
- * A simple domain socket listener
  * Original author : tridge at samba.org, January 2002
+ * 
+ * Copyright (c) 2005 Christophe Varoqui
+ * Copyright (c) 2005 Benjamin Marzinski, Redhat
+ */
+
+/*
+ * A simple domain socket listener
  */
 #include <stdio.h>
 #include <stdlib.h>
@@ -14,6 +20,8 @@
 #include <sys/un.h>
 #include <sys/poll.h>
 
+#include <checkers.h>
+
 #include <memory.h>
 #include <debug.h>
 #include <vector.h>

Modified: multipath-tools/trunk/path_priority/pp_alua/Makefile
==============================================================================
--- multipath-tools/trunk/path_priority/pp_alua/Makefile	(original)
+++ multipath-tools/trunk/path_priority/pp_alua/Makefile	Mon Mar 13 15:16:41 2006
@@ -17,6 +17,7 @@
 DEBUG		= 0
 DEBUG_DUMPHEX	= 0
 OBJS		= main.o rtpg.o
+INSTALL		= install -D
 
 TOPDIR	= ../..
 
@@ -24,7 +25,7 @@
 include $(TOPDIR)/Makefile.inc
 endif
 
-CFLAGS = -pipe -g -O2 -Wall -Wunused -Wstrict-prototypes -DDEBUG=$(DEBUG)
+CFLAGS += -DDEBUG=$(DEBUG)
 
 all: $(BUILD)
 
@@ -35,10 +36,8 @@
 	$(CC) -static -o $(EXEC) $(OBJS)
 
 install: $(BUILD) $(EXEC).8.gz
-	install -d $(DESTDIR)$(bindir)
-	install -m 755 $(EXEC) $(DESTDIR)$(bindir)/$(EXEC)
-	install -d $(DESTDIR)$(mandir)
-	install -m 644 $(EXEC).8.gz $(DESTDIR)$(mandir)
+	$(INSTALL) -m 755 $(EXEC) $(DESTDIR)$(bindir)/$(EXEC)
+	$(INSTALL) -m 644 $(EXEC).8.gz $(DESTDIR)$(mandir)/$(EXEC).8.gz
 
 uninstall:
 	rm $(DESTDIR)$(bindir)/$(EXEC)
@@ -47,9 +46,6 @@
 clean:	
 	rm -f *.o *.gz $(EXEC)
 
-%.o:	%.c
-	$(CC) $(CFLAGS) -c -o $@ $<
-
 $(EXEC).8.gz:	$(EXEC).8
 	$(GZIP) $< >$@
 

Modified: multipath-tools/trunk/path_priority/pp_balance_units/Makefile
==============================================================================
--- multipath-tools/trunk/path_priority/pp_balance_units/Makefile	(original)
+++ multipath-tools/trunk/path_priority/pp_balance_units/Makefile	Mon Mar 13 15:16:41 2006
@@ -9,16 +9,15 @@
 include $(TOPDIR)/Makefile.inc
 
 ifeq ($(strip $(BUILD)),klibc)
-	CFLAGS = -I/usr/include -DDEBUG=$(DEBUG)
+	CFLAGS += -I/usr/include -DDEBUG=$(DEBUG)
 	OBJS = pp_balance_units.o $(MULTIPATHLIB)-$(BUILD).a
 else
-	CFLAGS = -pipe -g -Wall -Wunused -Wstrict-prototypes \
-		 -I$(multipathdir) -DDEBUG=$(DEBUG)
+	CFLAGS += -I$(multipathdir) -DDEBUG=$(DEBUG)
 	LDFLAGS = -ldevmapper
 	OBJS = pp_balance_units.o $(MULTIPATHLIB)-$(BUILD).a
 endif
 
-EXEC = pp_balance_units
+EXEC = mpath_prio_balance_units
 
 all: $(BUILD)
 
@@ -27,7 +26,7 @@
 
 glibc: prepare $(OBJS)
 	$(CC) -o $(EXEC) $(OBJS) $(LDFLAGS)
-	
+
 klibc: prepare $(OBJS)
 	$(CC) -static -o $(EXEC) $(CRT0) $(OBJS) $(KLIBC) $(LIBGCC)
 

Modified: multipath-tools/trunk/path_priority/pp_emc/Makefile
==============================================================================
--- multipath-tools/trunk/path_priority/pp_emc/Makefile	(original)
+++ multipath-tools/trunk/path_priority/pp_emc/Makefile	Mon Mar 13 15:16:41 2006
@@ -5,8 +5,6 @@
 TOPDIR		= ../..
 include $(TOPDIR)/Makefile.inc
 
-CFLAGS = -pipe -g -O2 -Wall -Wunused -Wstrict-prototypes
-
 all: $(BUILD)
 
 glibc:	$(OBJS)

Added: multipath-tools/trunk/path_priority/pp_netapp/Makefile
==============================================================================
--- (empty file)
+++ multipath-tools/trunk/path_priority/pp_netapp/Makefile	Mon Mar 13 15:16:41 2006
@@ -0,0 +1,22 @@
+EXEC		= mpath_prio_netapp
+BUILD		= glibc
+OBJS		= pp_netapp.o
+
+TOPDIR		= ../..
+include $(TOPDIR)/Makefile.inc
+
+all: $(BUILD)
+
+glibc:	$(OBJS)
+	$(CC) -o $(EXEC) $(OBJS) $(LDFLAGS)
+
+klibc:	$(OBJS)
+	$(CC) -static -o $(EXEC) $(OBJS)
+
+install: $(EXEC)
+	install -s -m 755 $(EXEC) $(DESTDIR)$(bindir)/$(EXEC)
+
+uninstall:
+	rm $(DESTDIR)$(bindir)/$(EXEC)
+clean:	
+	rm -f *.o $(EXEC)

Added: multipath-tools/trunk/path_priority/pp_netapp/pp_netapp.c
==============================================================================
--- (empty file)
+++ multipath-tools/trunk/path_priority/pp_netapp/pp_netapp.c	Mon Mar 13 15:16:41 2006
@@ -0,0 +1,268 @@
+/* 
+ * Copyright 2005 Network Appliance, Inc., All Rights Reserved
+ * Author:  David Wysochanski available at davidw at netapp.com
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of 
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License v2 for more details.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <errno.h>
+#include <assert.h>
+
+#include "../../libmultipath/sg_include.h"
+
+#define INQUIRY_CMD	0x12
+#define INQUIRY_CMDLEN	6
+#define DEFAULT_PRIO	10
+#define RESULTS_MAX	256
+#define SG_TIMEOUT	30000
+
+
+static void dump_cdb(unsigned char *cdb, int size)
+{
+	int i;
+	
+	fprintf(stderr, "- SCSI CDB: ");
+	for (i=0; i<size; i++) {
+		fprintf(stderr, "0x%02x ", cdb[i]);
+	}
+	fprintf(stderr, "\n");
+}
+
+static void process_sg_error(struct sg_io_hdr *io_hdr)
+{
+	int i;
+	
+	fprintf(stderr, "- masked_status=0x%02x, host_status=0x%02x, "
+		"driver_status=0x%02x\n", io_hdr->masked_status,
+		io_hdr->host_status, io_hdr->driver_status);
+	if (io_hdr->sb_len_wr > 0) {
+		fprintf(stderr, "- SCSI sense data: ");
+		for (i=0; i<io_hdr->sb_len_wr; i++) {
+			fprintf(stderr, "0x%02x ", io_hdr->sbp[i]);
+		}
+		fprintf(stderr, "\n");
+	}
+}
+
+/*
+ * Returns:
+ * -1: error, errno set
+ *  0: success
+ */
+static int send_gva(const char *dev, unsigned char pg,
+		    unsigned char *results, int *results_size)
+{
+	unsigned char sb[128];
+	unsigned char cdb[10] = {0xc0, 0, 0x1, 0xa, 0x98, 0xa,
+				 pg, sizeof(sb), 0, 0};
+	struct sg_io_hdr io_hdr;
+	int ret = -1;
+	int fd;
+
+	fd = open(dev, O_RDWR|O_NONBLOCK);
+
+	if (fd <= 0) {
+		fprintf(stderr, "Opening %s failed, errno=%d.\n", dev, errno);
+		goto out_no_close;
+	}
+
+	memset(&io_hdr, 0, sizeof (struct sg_io_hdr));
+	io_hdr.interface_id = 'S';
+	io_hdr.cmd_len = sizeof (cdb);
+	io_hdr.mx_sb_len = sizeof (sb);
+	io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
+	io_hdr.dxfer_len = *results_size;
+	io_hdr.dxferp = results;
+	io_hdr.cmdp = cdb;
+	io_hdr.sbp = sb;
+	io_hdr.timeout = SG_TIMEOUT;
+	io_hdr.pack_id = 0;
+	if (ioctl(fd, SG_IO, &io_hdr) < 0) {
+		fprintf(stderr, "SG_IO ioctl failed, errno=%d\n", errno);
+		dump_cdb(cdb, sizeof(cdb));
+		goto out;
+	}
+	if (io_hdr.info & SG_INFO_OK_MASK) {
+		fprintf(stderr, "SCSI error\n");
+		dump_cdb(cdb, sizeof(cdb));
+		process_sg_error(&io_hdr);
+		goto out;
+	}
+
+	if (results[4] != 0x0a || results[5] != 0x98 ||
+	    results[6] != 0x0a ||results[7] != 0x01) {
+		dump_cdb(cdb, sizeof(cdb));
+		fprintf(stderr, "GVA return wrong format ");
+		fprintf(stderr, "results[4-7] = 0x%02x 0x%02x 0x%02x 0x%02x\n",
+			results[4], results[5], results[6], results[7]);
+		goto out;
+	}
+	ret = 0;
+ out:
+	close(fd);
+ out_no_close:
+	return(ret);
+}
+
+/*
+ * Retuns:
+ * -1: Unable to obtain proxy info
+ *  0: Device _not_ proxy path
+ *  1: Device _is_ proxy path
+ */
+static int get_proxy(const char *dev)
+{
+	unsigned char results[256];
+	unsigned char sb[128];
+	unsigned char cdb[INQUIRY_CMDLEN] = {INQUIRY_CMD, 1, 0xc1, 0,
+						   sizeof(sb), 0};
+	struct sg_io_hdr io_hdr;
+	int ret = -1;
+	int fd;
+
+	fd = open(dev, O_RDWR|O_NONBLOCK);
+
+	if (fd <= 0) {
+		fprintf(stderr, "Opening %s failed, errno=%d.\n", dev, errno);
+		goto out_no_close;
+	}
+
+	memset(&results, 0, sizeof (results));
+	memset(&io_hdr, 0, sizeof (struct sg_io_hdr));
+	io_hdr.interface_id = 'S';
+	io_hdr.cmd_len = sizeof (cdb);
+	io_hdr.mx_sb_len = sizeof (sb);
+	io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
+	io_hdr.dxfer_len = sizeof (results);
+	io_hdr.dxferp = results;
+	io_hdr.cmdp = cdb;
+	io_hdr.sbp = sb;
+	io_hdr.timeout = SG_TIMEOUT;
+	io_hdr.pack_id = 0;
+	if (ioctl(fd, SG_IO, &io_hdr) < 0) {
+		fprintf(stderr, "ioctl sending inquiry command failed, "
+			"errno=%d\n", errno);
+		dump_cdb(cdb, sizeof(cdb));
+		goto out;
+	}
+	if (io_hdr.info & SG_INFO_OK_MASK) {
+		fprintf(stderr, "SCSI error\n");
+		dump_cdb(cdb, sizeof(cdb));
+		process_sg_error(&io_hdr);
+		goto out;
+	}
+
+	if (results[1] != 0xc1 || results[8] != 0x0a ||
+	    results[9] != 0x98 || results[10] != 0x0a ||
+	    results[11] != 0x0 || results[12] != 0xc1 ||
+	    results[13] != 0x0) {
+		fprintf(stderr,"Proxy info page in unknown format - ");
+		fprintf(stderr,"results[8-13]=0x%02x 0x%02x 0x%02x 0x%02x "
+			"0x%02x 0x%02x\n",
+			results[8], results[9], results[10],
+			results[11], results[12], results[13]);
+		dump_cdb(cdb, sizeof(cdb));
+		goto out;
+	}
+	ret = (results[19] & 0x02) >> 1;
+
+ out:
+	close(fd);
+ out_no_close:
+	return(ret);
+}
+
+/*
+ * Returns priority of device based on device info.
+ *
+ * 4: FCP non-proxy, FCP proxy unknown, or unable to determine protocol
+ * 3: iSCSI HBA
+ * 2: iSCSI software
+ * 1: FCP proxy
+ */
+static int netapp_prio(const char *dev)
+{
+	unsigned char results[RESULTS_MAX];
+	int results_size=RESULTS_MAX;
+	int rc;
+	int is_proxy;
+	int is_iscsi_software;
+	int is_iscsi_hardware;
+	int tot_len;
+
+	is_iscsi_software = is_iscsi_hardware = is_proxy = 0;
+
+	memset(&results, 0, sizeof (results));
+	rc = send_gva(dev, 0x41, results, &results_size);
+	if (rc == 0) {
+		tot_len = results[0] << 24 | results[1] << 16 |
+			  results[2] << 8 | results[3];
+		if (tot_len <= 8) {
+			goto try_fcp_proxy;
+		}
+		if (results[8] != 0x41) {
+			fprintf(stderr, "GVA page 0x41 error - "
+				"results[8] = 0x%x\n", results[8]);
+			goto try_fcp_proxy;
+		}
+		if ((strncmp((char *)&results[12], "ism_sw", 6) == 0) ||
+		    (strncmp((char *)&results[12], "iswt", 4) == 0)) {
+			is_iscsi_software = 1;
+			goto prio_select;
+		}
+		else if (strncmp((char *)&results[12], "ism_sn", 6) == 0) {
+			is_iscsi_hardware = 1;
+			goto prio_select;
+		}
+	}
+	
+ try_fcp_proxy:	
+	rc = get_proxy(dev);
+	if (rc >= 0) {
+		is_proxy = rc;
+	}
+
+ prio_select:
+	if (is_iscsi_hardware) {
+		return 3;
+	} else if (is_iscsi_software) {
+		return 2;
+	} else {
+		if (is_proxy) {
+			return 1;
+		} else {
+			/* Either non-proxy, or couldn't get proxy info */
+			return 4;
+		}
+	}
+}
+
+int
+main (int argc, char **argv)
+{
+	int prio;
+	if (argc != 2) {
+		fprintf(stderr, "Arguments wrong!\n");
+		prio = 0;
+	} else
+		prio = netapp_prio(argv[1]);
+	
+	printf("%d\n", prio);
+	exit(0);
+}
+

Modified: multipath-tools/trunk/path_priority/pp_random/Makefile
==============================================================================
--- multipath-tools/trunk/path_priority/pp_random/Makefile	(original)
+++ multipath-tools/trunk/path_priority/pp_random/Makefile	Mon Mar 13 15:16:41 2006
@@ -5,8 +5,6 @@
 TOPDIR		= ../..
 include $(TOPDIR)/Makefile.inc
 
-CFLAGS = -pipe -g -O2 -Wall -Wunused -Wstrict-prototypes
-
 all: $(BUILD)
 
 glibc:	$(OBJS)
@@ -23,6 +21,3 @@
 	rm $(DESTDIR)$(bindir)/$(EXEC)
 clean:	
 	rm -f *.o $(EXEC)
-
-%.o:	%.c
-	$(CC) $(CFLAGS) -c -o $@ $<

Added: multipath-tools/trunk/path_priority/pp_tpc/Makefile
==============================================================================
--- (empty file)
+++ multipath-tools/trunk/path_priority/pp_tpc/Makefile	Mon Mar 13 15:16:41 2006
@@ -0,0 +1,22 @@
+EXEC		= mpath_prio_tpc
+BUILD		= glibc
+OBJS		= pp_tpc.o
+
+TOPDIR		= ../..
+include $(TOPDIR)/Makefile.inc
+
+all: $(BUILD)
+
+glibc:	$(OBJS)
+	$(CC) -o $(EXEC) $(OBJS) $(LDFLAGS)
+
+klibc:	$(OBJS)
+	$(CC) -static -o $(EXEC) $(OBJS)
+
+install: $(EXEC)
+	install -s -m 755 $(EXEC) $(DESTDIR)$(bindir)/$(EXEC)
+
+uninstall:
+	rm $(DESTDIR)$(bindir)/$(EXEC)
+clean:	
+	rm -f *.o $(EXEC)

Added: multipath-tools/trunk/path_priority/pp_tpc/pp_tpc.c
==============================================================================
--- (empty file)
+++ multipath-tools/trunk/path_priority/pp_tpc/pp_tpc.c	Mon Mar 13 15:16:41 2006
@@ -0,0 +1,118 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <errno.h>
+
+#include "../../libmultipath/sg_include.h"
+
+#define INQUIRY_CMD     0x12
+#define INQUIRY_CMDLEN  6
+
+int sgi_tpc_prio(const char *dev)
+{
+	unsigned char sense_buffer[256];
+	unsigned char sb[128];
+	unsigned char inqCmdBlk[INQUIRY_CMDLEN] = {INQUIRY_CMD, 1, 0xC9, 0,
+						sizeof(sb), 0};
+	struct sg_io_hdr io_hdr;
+	int ret = 0;
+	int fd;
+
+	fd = open(dev, O_RDWR|O_NONBLOCK);
+
+	if (fd <= 0) {
+		fprintf(stderr, "opening of the device failed.\n");
+		goto out;
+	}
+
+	memset(&io_hdr, 0, sizeof (struct sg_io_hdr));
+	io_hdr.interface_id = 'S';
+	io_hdr.cmd_len = sizeof (inqCmdBlk);
+	io_hdr.mx_sb_len = sizeof (sb);
+	io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
+	io_hdr.dxfer_len = sizeof (sense_buffer);
+	io_hdr.dxferp = sense_buffer;
+	io_hdr.cmdp = inqCmdBlk;
+	io_hdr.sbp = sb;
+	io_hdr.timeout = 60000;
+	io_hdr.pack_id = 0;
+	if (ioctl(fd, SG_IO, &io_hdr) < 0) {
+		fprintf(stderr, "sending inquiry command failed\n");
+		goto out;
+	}
+	if (io_hdr.info & SG_INFO_OK_MASK) {
+		fprintf(stderr, "inquiry command indicates error");
+		goto out;
+	}
+
+	close(fd);
+	
+	if (/* Verify the code page - right page & page identifier */
+	    sense_buffer[1] != 0xc9 || 
+	    sense_buffer[3] != 0x2c ||
+	    sense_buffer[4] != 'v' ||
+	    sense_buffer[5] != 'a' ||
+	    sense_buffer[6] != 'c' ) {
+		fprintf(stderr, "Volume access control page in unknown format");
+		goto out;
+	}
+	
+	if ( /* Auto-volume Transfer Enabled */
+	    	(sense_buffer[8] & 0x80) != 0x80 ) {
+		fprintf(stderr, "Auto-volume Transfer not enabled");
+	}
+
+	if ( /* Current Volume Path Bit */
+		( sense_buffer[8] & 0x01) == 0x01 ) {
+		/* 
+		 * This volume was owned by the controller receiving
+		 * the inquiry command.
+		 */
+		ret |= 0x02;
+	}
+
+	/* Volume Preferred Path Priority */
+	switch ( sense_buffer[9] & 0x0F ) {
+	case 0x01:
+		/* 
+		 * Access to this volume is most preferred through
+		 * this path and other paths with this value.
+		 */
+		ret |= 0x04;
+		break;
+	case 0x02:
+		/*
+		 * Access to this volume through this path is to be used
+		 * as a secondary path. Typically this path would be used
+		 * for fail-over situations.
+		 */
+		ret |= 0x01;
+		break;
+	default:
+		/* Reserved values */
+		break;
+	}
+	
+out:
+	return(ret);
+}
+
+int
+main (int argc, char **argv)
+{
+	int prio;
+	if (argc != 2) {
+		fprintf(stderr, "Wrong number of arguments.\n");
+		fprintf(stderr, "Usage: %s device\n", argv[0]);
+		prio = 0;
+	} else
+		prio = sgi_tpc_prio(argv[1]);
+
+	printf("%d\n", prio);
+	exit(0);
+}



More information about the pkg-lvm-commits mailing list