2 * FCP report generators
4 * Utility classes to read and access FCP configuration information
6 * Copyright IBM Corp. 2008
7 * Author(s): Stefan Raspl <raspl@linux.vnet.ibm.com>
16 #include "ziorep_cfgreader.hpp"
17 #include "ziorep_filters.hpp"
18 #include "ziorep_utils.hpp"
20 #define ZIOREP_CFG_EXTENSION ".cfg"
21 #define ZIOREP_CONFIG_PATH "/sbin/ziorep_config"
23 extern const char *toolname
;
27 ConfigReader::ConfigReader(int *rc
, const char *filename
)
28 : m_tmp_file(NULL
), m_cfg_cached(false)
31 struct device_info new_elem
;
36 long long unsigned int tmp_lun
;
37 long long unsigned int tmp_wwpn
;
41 if (check_config_file(filename
)) {
46 if (extract_config_data(filename
)) {
51 init_device_info(&new_elem
);
53 verbose_msg("ConfigReader: reading from %s\n", m_tmp_file
);
55 fp
= fopen(m_tmp_file
, "r");
57 fprintf(stderr
, "%s: Could not open config file %s\n", toolname
, m_tmp_file
);
59 goto out_fp_not_opened
;
61 while ( (lrc
= getline(&line
, &line_len
, fp
)) >= 0) {
62 // allocation could be improved...
63 init_device_info(&new_elem
);
64 new_elem
.device
= (char*)malloc(lrc
+ 1);
65 new_elem
.type
= (char*)malloc(lrc
+ 1);
66 new_elem
.multipath_device
= (char*)malloc(lrc
+ 1);
67 lrc
= sscanf(line
, "%x %u:%u:%u:%u 0.0.%x:0.0.%x:%Lx:%Lx %s %u %u:%u %s %u %u:%u %s",
69 &new_elem
.hctl_identifier
.host
,
70 &new_elem
.hctl_identifier
.channel
,
71 &new_elem
.hctl_identifier
.target
,
72 &new_elem
.hctl_identifier
.lun
,
73 &new_elem
.subchannel
, &new_elem
.devno
,
76 new_elem
.multipath_device
, &new_elem
.mp_mm
,
78 &new_elem
.mp_minor
, new_elem
.device
,
79 &new_elem
.mm_internal
,
80 &new_elem
.major
, &new_elem
.minor
,
85 fprintf(stderr
, "%s: Could not parse line %d"
86 " - configuration file broken?\n", toolname
, line_idx
);
90 new_elem
.wwpn
= tmp_wwpn
;
91 new_elem
.lun
= tmp_lun
;
93 if (strcmp(new_elem
.multipath_device
, "n/a") == 0) {
94 free(new_elem
.multipath_device
);
95 new_elem
.multipath_device
= NULL
;
96 new_elem
.mp_major
= 0;
97 new_elem
.mp_minor
= 0;
99 m_devices
.push_back(new_elem
);
102 init_device_info(&new_elem
);
104 if (filter_unused_devices(filename
)) {
109 verbose_msg("ConfigReader: done\n");
114 free_device_info(&new_elem
);
118 if (!m_cfg_cached
|| *rc
)
126 ConfigReader::~ConfigReader()
128 for (list
<struct device_info
>::iterator i
= m_devices
.begin();
129 i
!= m_devices
.end(); ++i
)
130 free_device_info(&(*i
));
134 int ConfigReader::filter_unused_devices(const char *filename
)
136 DeviceFilter dev_filt
;
139 if (get_all_devices(filename
, dev_filt
, *this))
142 for (list
<struct device_info
>::iterator i
= m_devices
.begin();
143 i
!= m_devices
.end();) {
144 if (!dev_filt
.is_eligible_mm((*i
).mm_internal
)) {
145 verbose_msg(" device %u:%u not in data, remove\n",
146 (*i
).major
, (*i
).minor
);
147 free_device_info(&(*i
));
148 i
= m_devices
.erase(i
);
154 verbose_msg("removed %d of %lu devices\n", j
,
155 (long unsigned int)(m_devices
.size() + j
));
161 int ConfigReader::check_ziorep_config() const
163 if (access(ZIOREP_CONFIG_PATH
, F_OK
| R_OK
| X_OK
)) {
164 fprintf(stderr
, "%s: Cannot access " ZIOREP_CONFIG_PATH
165 ". Please check your installation and try again.\n", toolname
);
173 int ConfigReader::check_config_file(const char *fname
) const
178 tmp
= (char*)malloc(strlen(fname
) + strlen(ZIOREP_CFG_EXTENSION
) + 1);
179 sprintf(tmp
, "%s%s", fname
, ZIOREP_CFG_EXTENSION
);
181 if (access(tmp
, F_OK
| R_OK
)) {
182 fprintf(stderr
, "%s: Cannot access config file %s."
183 " Please make sure that you get the matching .cfg"
184 " file for your data.\n", toolname
, tmp
);
192 #define ZIOREP_TMP_TEMPLATE "/tmp/ziorepXXXXXX"
193 #define ZIOREP_CONFIG_EXT ".config"
196 int ConfigReader::extract_config_data(const char *fname
)
198 verbose_msg("Check config data...\n");
199 if (cached_config_exists(fname
)) {
200 verbose_msg("Cached file found, reusing.\n");
205 // Try to extract to .config first, which will be permanently cached
206 verbose_msg("No data cached, extract\n");
207 if (check_ziorep_config())
210 fprintf(stdout
, "Extracting config data...");
212 if (extract_cached(fname
)) {
213 verbose_msg("Could not create %s file, create tmp file\n",
215 if (extract_tmp(fname
)) {
216 fprintf(stderr
, "%s: Could not extract"
217 " configuration data. Check the integrity of"
218 " %s%s with %s and retry.", toolname
, fname
,
219 ZIOREP_CFG_EXTENSION
, ZIOREP_CONFIG_PATH
);
224 fprintf(stdout
, "done\n");
226 verbose_msg("Check config data finished\n");
232 int ConfigReader::extract_cached(const char *fname
)
234 assert(m_tmp_file
== NULL
);
236 m_tmp_file
= (char*)malloc(strlen(fname
) + strlen(ZIOREP_CONFIG_EXT
)
238 sprintf(m_tmp_file
, "%s%s", fname
, ZIOREP_CONFIG_EXT
);
240 if (extract(fname
)) {
241 // we can't guarantee that something was not written,
242 // hence we remove the file anyway to avoid stumbling
243 // over a broken .config file next time
255 int ConfigReader::extract_tmp(const char *fname
)
259 assert(m_tmp_file
== NULL
);
261 m_tmp_file
= (char*)malloc(strlen(ZIOREP_TMP_TEMPLATE
) + 1);
262 strcpy(m_tmp_file
, ZIOREP_TMP_TEMPLATE
);
264 if (mkstemp(m_tmp_file
) == -1) {
265 fprintf(stdout
, "Error: Could not create temporary"
266 " filename: %s\n", strerror(errno
));
283 int ConfigReader::extract(const char *fname
)
288 // /sbin/ziorep_config -I -i <fname.cfg> > <file> 2>/dev/null
289 cmd
= (char*)malloc(strlen(ZIOREP_CONFIG_PATH
) + 7 + strlen(fname
)
290 + strlen(ZIOREP_CFG_EXTENSION
) + 3 + strlen(m_tmp_file
)
293 sprintf(cmd
, "%s -I -i %s%s > %s 2>/dev/null", ZIOREP_CONFIG_PATH
, fname
,
294 ZIOREP_CFG_EXTENSION
, m_tmp_file
);
296 verbose_msg("Issue command: %s\n", cmd
);
302 verbose_msg("Data extracted to %s\n", m_tmp_file
);
310 bool ConfigReader::cached_config_exists(const char *fname
)
314 m_tmp_file
= (char*)malloc(strlen(fname
) + strlen(ZIOREP_CONFIG_EXT
)
316 sprintf(m_tmp_file
, "%s%s", fname
, ZIOREP_CONFIG_EXT
);
318 if (access(m_tmp_file
, R_OK
)) {
319 verbose_msg("No cached file found.\n");
329 int ConfigReader::extract_adapter_info_sub(char **tgt
, char *p
, char delim
)
333 offset
= get_index_to(p
, delim
);
336 *tgt
= (char*)malloc(offset
+ 1);
337 strncpy(*tgt
, p
, offset
);
338 (*tgt
)[offset
] = '\0';
344 void ConfigReader::init_device_info(struct device_info
*info
)
346 info
->multipath_device
= NULL
;
352 void ConfigReader::free_device_info(struct device_info
*info
)
354 free(info
->multipath_device
);
355 info
->multipath_device
= NULL
;
363 int ConfigReader::get_index_to(char *p
, char c
) const
367 for (i
= 0; *p
!= c
&& *p
!= '\0'; ++p
, ++i
) ;
373 void ConfigReader::host_id_not_found_error(__u32 h
, int *rc
) const
376 fprintf(stderr
, "%s: Could not find host index %u in configuration"
377 " file. Please check if you have the right .cfg file and try"
378 " again\n", toolname
, h
);
382 void ConfigReader::devno_not_found_error(__u32 devno
, int *rc
) const
385 fprintf(stderr
, "%s: Could not find bus id 0.0.%x in configuration"
386 " file. Please check if you have the right .cfg file and try"
387 " again\n", toolname
, devno
);
391 void ConfigReader::chpid_not_found_error(__u32 chpid
, int *rc
) const
394 fprintf(stderr
, "%s: Could not find chpid %x in configuration"
395 " file. Please check if you have the right .cfg file and try"
396 " again\n", toolname
, chpid
);
400 void ConfigReader::lun_not_found_error(__u64 lun
, int *rc
) const
403 fprintf(stderr
, "%s: Could not find LUN %016Lx in configuration"
404 " file. Please check if you have the right .cfg file and try"
405 " again\n", toolname
, (long long unsigned int)lun
);
409 void ConfigReader::ident_not_found_error(const struct hctl_ident
*ident
, int *rc
) const
412 fprintf(stderr
, "%s: Could not find identifier [%d:%d:%d:%d] in"
413 " configuration file. Please check if you have the right .cfg"
414 " file and try again\n", toolname
, ident
->host
, ident
->channel
,
415 ident
->target
, ident
->lun
);
419 void ConfigReader::mm_internal_not_found_error(__u32 mm
, int *rc
) const
422 fprintf(stderr
, "%s: Could not find device with internal mm %u in"
423 " configuration file. Please check if you have the right .cfg"
424 " file and try again\n", toolname
, mm
);
428 void ConfigReader::device_not_found_error(const char *dev
, int *rc
) const
431 fprintf(stderr
, "%s: Could not find device %s in"
432 " configuration file. Please check if you have the right .cfg"
433 " file and try again\n", toolname
, dev
);
437 void ConfigReader::mp_not_found_error(const char *mp
, int *rc
) const
440 fprintf(stderr
, "%s: Could not find multipath device %s in"
441 " configuration file. Please check if you have the right .cfg"
442 " file and try again\n", toolname
, mp
);
446 void ConfigReader::mp_mm_not_found_error(__u32 mp_mm
, int *rc
) const
449 fprintf(stderr
, "%s: Could not find multipath device %ud in"
450 " configuration file. Please check if you have the right .cfg"
451 " file and try again\n", toolname
, mp_mm
);
455 #define search_for(att, crit, ret) for (list<struct device_info>::const_iterator i = m_devices.begin(); \
456 i != m_devices.end(); ++i) { \
457 if ((*i).att == crit) \
461 #define search_for_by_dev(crit, ret) for (list<struct device_info>::const_iterator i = m_devices.begin(); \
462 i != m_devices.end(); ++i) { \
463 if (compare_hctl_idents(&(*i).hctl_identifier, crit) == 0) \
467 __u32
ConfigReader::get_chpid_by_host_id(__u32 host
, int *rc
) const
469 search_for(hctl_identifier
.host
, host
, chpid
);
471 host_id_not_found_error(host
, rc
);
477 __u32
ConfigReader::get_chpid_by_devno(__u32 d
, int *rc
) const
479 search_for(devno
, d
, chpid
);
481 devno_not_found_error(d
, rc
);
487 __u32
ConfigReader::get_chpid_by_ident(const struct hctl_ident
*ident
, int *rc
) const
489 search_for_by_dev(ident
, chpid
);
491 ident_not_found_error(ident
, rc
);
497 __u32
ConfigReader::get_chpid_by_mm_internal(__u32 mm
, int *rc
) const
499 search_for(mm_internal
, mm
, chpid
);
501 mm_internal_not_found_error(mm
, rc
);
507 __u32
ConfigReader::get_host_id_by_chpid(__u32 chpid
, int *rc
) const
509 search_for(chpid
, chpid
, hctl_identifier
.host
);
511 chpid_not_found_error(chpid
, rc
);
517 __u32
ConfigReader::get_devno_by_host_id(__u32 host
, int *rc
) const
519 search_for(hctl_identifier
.host
, host
, devno
);
521 host_id_not_found_error(host
, rc
);
527 __u32
ConfigReader::get_devno_by_ident(const struct hctl_ident
*ident
,
530 search_for_by_dev(ident
, devno
);
532 ident_not_found_error(ident
, rc
);
538 __u32
ConfigReader::get_devno_by_mm_internal(__u32 mm
, int *rc
) const
540 search_for(mm_internal
, mm
, devno
);
542 mm_internal_not_found_error(mm
, rc
);
548 __u32
ConfigReader::get_mp_mm_by_multipath(const char* mp
, int *rc
) const
550 for (list
<struct device_info
>::const_iterator i
= m_devices
.begin();
551 i
!= m_devices
.end(); ++i
) {
552 if ((*i
).multipath_device
553 && strcmp((*i
).multipath_device
+ strlen("/dev/mapper/"),
558 mp_not_found_error(mp
, rc
);
564 const char* ConfigReader::get_multipath_by_mp_mm(__u32 mp_mm
, int *rc
) const
566 search_for(mp_mm
, mp_mm
, multipath_device
);
568 mp_mm_not_found_error(mp_mm
, rc
);
574 __u64
ConfigReader::get_wwpn_by_mm_internal(__u32 dev
, int *rc
) const
576 search_for(mm_internal
, dev
, wwpn
);
578 mm_internal_not_found_error(dev
, rc
);
584 __u64
ConfigReader::get_wwpn_by_ident(const struct hctl_ident
*ident
, int *rc
) const
586 search_for_by_dev(ident
, wwpn
);
588 ident_not_found_error(ident
, rc
);
594 __u32
ConfigReader::get_mp_mm_by_mm_internal(__u32 mm
, int *rc
) const
596 search_for(mm_internal
, mm
, mp_mm
);
598 mm_internal_not_found_error(mm
, rc
);
604 __u32
ConfigReader::get_mp_mm_by_ident(const struct hctl_ident
*ident
, int *rc
) const
606 search_for_by_dev(ident
, mp_mm
);
608 ident_not_found_error(ident
, rc
);
614 __u64
ConfigReader::get_lun_by_mm_internal(__u32 mm
, int *rc
) const
616 search_for(mm_internal
, mm
, lun
);
618 mm_internal_not_found_error(mm
, rc
);
623 const char* ConfigReader::get_dev_by_mm_internal(__u32 mm
, int *rc
) const
625 search_for(mm_internal
, mm
, device
);
627 mm_internal_not_found_error(mm
, rc
);
629 return "<invalid device>";
632 __u32
ConfigReader::get_mm_by_ident(const struct hctl_ident
*id
, int *rc
) const
634 search_for_by_dev(id
, mm_internal
);
636 ident_not_found_error(id
, rc
);
641 __u32
ConfigReader::get_mm_by_device(const char *dev
, int *rc
) const
643 for (list
<struct device_info
>::const_iterator i
= m_devices
.begin();
644 i
!= m_devices
.end(); ++i
) {
645 if (strcmp((*i
).device
+ strlen("/dev/"), dev
) == 0)
646 return (*i
).mm_internal
;
649 device_not_found_error(dev
, rc
);
654 const struct hctl_ident
* ConfigReader::get_ident_by_mm_internal(__u32 mm
, int *rc
) const
656 for (list
<struct device_info
>::const_iterator i
= m_devices
.begin();
657 i
!= m_devices
.end(); ++i
) {
658 if ((*i
).mm_internal
== mm
)
659 return &(*i
).hctl_identifier
;
662 mm_internal_not_found_error(mm
, rc
);
668 #define get_uniq(tgt, a, type) tgt.clear(); \
669 for (list<struct device_info>::const_iterator i = m_devices.begin(); \
670 i != m_devices.end(); ++i) { \
671 list<type>::iterator j; \
672 for (j = tgt.begin(); j != tgt.end() && (*i).a != (*j); ++j); \
673 if (j == tgt.end()) \
674 tgt.push_back((*i).a); \
678 void ConfigReader::get_unique_wwpns(list
<__u64
> &wwpns
) const
680 get_uniq(wwpns
, wwpn
, __u64
);
684 void ConfigReader::get_unique_devnos(list
<__u32
> &devnos
) const
686 get_uniq(devnos
, devno
, __u32
);
690 void ConfigReader::get_unique_chpids(list
<__u32
> &chpids
) const
692 get_uniq(chpids
, chpid
, __u32
);
696 void ConfigReader::get_unique_host_ids(list
<__u32
> &host_ids
) const
698 get_uniq(host_ids
, hctl_identifier
.host
, __u32
);
702 void ConfigReader::get_unique_mp_mms(list
<__u32
> &mp_mms
) const
705 for (list
<struct device_info
>::const_iterator i
= m_devices
.begin();
706 i
!= m_devices
.end(); ++i
) {
707 list
<__u32
>::iterator j
;
708 for (j
= mp_mms
.begin();
709 j
!= mp_mms
.end() && (*i
).mp_mm
!= (*j
); ++j
) ;
710 /* Watch out: Always check the multipath_device attribute
711 to see whether the mp_mm is valid or not! */
712 if (j
== mp_mms
.end() && (*i
).multipath_device
!= NULL
)
713 mp_mms
.push_back((*i
).mp_mm
);
718 void ConfigReader::get_unique_mms(list
<__u32
> &lst
) const
721 for (list
<struct device_info
>::const_iterator i
= m_devices
.begin();
722 i
!= m_devices
.end(); ++i
)
723 // devices are unique by definition!
724 lst
.push_back((*i
).mm_internal
);
728 void ConfigReader::get_unique_devices(list
<struct hctl_ident
> &idents
) const
731 for (list
<struct device_info
>::const_iterator i
= m_devices
.begin();
732 i
!= m_devices
.end(); ++i
) {
733 // devices are unique by definition!
734 idents
.push_back((*i
).hctl_identifier
);
739 void ConfigReader::get_devnos_by_chpid(list
<__u32
> &devnos
, __u32 chpid
) const
742 for (list
<struct device_info
>::const_iterator i
= m_devices
.begin();
743 i
!= m_devices
.end(); ++i
) {
744 if ((*i
).chpid
== chpid
)
745 devnos
.push_back((*i
).devno
);
750 void ConfigReader::get_devnos_by_host_id(list
<__u32
> &devnos
, __u32 host_id
) const
753 for (list
<struct device_info
>::const_iterator i
= m_devices
.begin();
754 i
!= m_devices
.end(); ++i
) {
755 if ((*i
).hctl_identifier
.host
== host_id
)
756 devnos
.push_back((*i
).devno
);
761 #define get_mms_list(lst, crit, val) lst.clear(); \
762 for (list<struct device_info>::const_iterator i = m_devices.begin(); \
763 i != m_devices.end(); ++i) { \
764 if ((*i).crit == val) \
765 lst.push_back((*i).mm_internal); \
768 void ConfigReader::get_mms_by_chpid(list<__u32> &mms, __u32 chpid) const
770 get_mms_list(mms
, chpid
, chpid
);
773 void ConfigReader::get_mms_by_mp_mm(list
<__u32
> &mms
, __u32 mp_mm
) const
775 get_mms_list(mms
, mp_mm
, mp_mm
);
778 void ConfigReader::get_mms_by_wwpn(list
<__u32
> &mms
, __u64 wwpn
) const
780 get_mms_list(mms
, wwpn
, wwpn
);
783 void ConfigReader::get_mms_by_devno(list
<__u32
> &mms
, __u32 d
) const
785 get_mms_list(mms
, devno
, d
);
788 void ConfigReader::get_mms_by_lun(list
<__u32
> &mms
, __u64 l
) const
790 get_mms_list(mms
, lun
, l
);
793 #define verify_numeric(criterion, val) for \
794 (list<struct device_info>::const_iterator \
795 i = m_devices.begin(); i != m_devices.end(); ++i) { \
796 if ((*i).criterion == val) \
802 #define verify_char(criterion, val, rc) for \
803 (list<struct device_info>::const_iterator \
804 i = m_devices.begin(); i != m_devices.end(); ++i) { \
805 if (val && (*i).criterion && strcmp((*i).criterion, val) == 0) \
810 bool ConfigReader::verify_chpid(__u32 c
) const
812 verify_numeric(chpid
, c
);
816 bool ConfigReader::verify_device(const char *dev
) const
821 tmp
= (char*)malloc(strlen(dev
) + strlen("/dev/") + 1);
822 sprintf(tmp
, "/dev/%s", dev
);
824 verify_char(device
, tmp
, rc
);
832 bool ConfigReader::verify_mp_device(const char *mp
) const
837 tmp
= (char*)malloc(strlen(mp
) + strlen("/dev/mapper/") + 1);
838 sprintf(tmp
, "/dev/mapper/%s", mp
);
840 verify_char(multipath_device
, tmp
, rc
);
848 bool ConfigReader::verify_wwpn(__u64 w
) const
850 verify_numeric(wwpn
, w
);
854 bool ConfigReader::verify_devno(__u32 d
) const
856 verify_numeric(devno
, d
);
860 bool ConfigReader::verify_lun(__u64 l
) const
862 verify_numeric(lun
, l
);
866 void ConfigReader::dump(FILE *fp
) const
868 fprintf(fp
, "dumping cfg....\n");
869 for (list
<struct device_info
>::const_iterator i
= m_devices
.begin();
870 i
!= m_devices
.end(); ++i
) {
871 fprintf(fp
, "%x %u %u:%u:%u:%u 0.0.%04x:0.0.%x:%016Lx:%016Lx %s %u:%u %s %u:%u %s\n",
872 (*i
).chpid
, (*i
).mm_internal
,
873 (*i
).hctl_identifier
.host
,
874 (*i
).hctl_identifier
.channel
,
875 (*i
).hctl_identifier
.target
,
876 (*i
).hctl_identifier
.lun
,
877 (*i
).subchannel
, (*i
).devno
,
878 (long long unsigned int)(*i
).wwpn
,
879 (long long unsigned int)(*i
).lun
,
880 ((*i
).multipath_device
? (*i
).multipath_device
: "n/a"), (*i
).mp_major
,
881 (*i
).mp_minor
, (*i
).device
,
882 (*i
).major
, (*i
).minor
,