Import version 1.8.3
[s390-tools.git] / ziomon / ziorep_cfgreader.cpp
blobc64c150ed71972318086894d2b935982e353410e
1 /*
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>
8 */
10 #include <unistd.h>
11 #include <string.h>
12 #include <stdlib.h>
13 #include <errno.h>
14 #include <assert.h>
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;
24 extern int verbose;
27 ConfigReader::ConfigReader(int *rc, const char *filename)
28 : m_tmp_file(NULL), m_cfg_cached(false)
30 FILE *fp = NULL;
31 struct device_info new_elem;
32 char *line = NULL;
33 size_t line_len;
34 int lrc;
35 int line_idx = 1;
36 long long unsigned int tmp_lun;
37 long long unsigned int tmp_wwpn;
39 *rc = 0;
41 if (check_config_file(filename)) {
42 *rc = -1;
43 return;
46 if (extract_config_data(filename)) {
47 *rc = -2;
48 return;
51 init_device_info(&new_elem);
53 verbose_msg("ConfigReader: reading from %s\n", m_tmp_file);
55 fp = fopen(m_tmp_file, "r");
56 if (!fp) {
57 fprintf(stderr, "%s: Could not open config file %s\n", toolname, m_tmp_file);
58 *rc = -1;
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",
68 &new_elem.chpid,
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,
74 &tmp_wwpn,
75 &tmp_lun,
76 new_elem.multipath_device, &new_elem.mp_mm,
77 &new_elem.mp_major,
78 &new_elem.mp_minor, new_elem.device,
79 &new_elem.mm_internal,
80 &new_elem.major, &new_elem.minor,
81 new_elem.type);
82 free(line);
83 line = NULL;
84 if (lrc != 18) {
85 fprintf(stderr, "%s: Could not parse line %d"
86 " - configuration file broken?\n", toolname, line_idx);
87 *rc = -1;
88 goto out;
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);
100 ++line_idx;
102 init_device_info(&new_elem);
104 if (filter_unused_devices(filename)) {
105 *rc = -2;
106 goto out;
109 verbose_msg("ConfigReader: done\n");
111 out:
112 fclose(fp);
113 out_fp_not_opened:
114 free_device_info(&new_elem);
115 free(line);
117 if (m_tmp_file) {
118 if (!m_cfg_cached || *rc)
119 remove(m_tmp_file);
120 free(m_tmp_file);
121 m_tmp_file = NULL;
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;
137 int j = 0;
139 if (get_all_devices(filename, dev_filt, *this))
140 return -1;
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);
149 j++;
151 else
152 ++i;
154 verbose_msg("removed %d of %lu devices\n", j,
155 (long unsigned int)(m_devices.size() + j));
157 return 0;
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);
166 return -1;
169 return 0;
173 int ConfigReader::check_config_file(const char *fname) const
175 char *tmp;
176 int rc = 0;
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);
185 rc = -1;
187 free(tmp);
189 return rc;
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");
201 m_cfg_cached = true;
202 return 0;
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())
208 return -1;
210 fprintf(stdout, "Extracting config data...");
211 fflush(stdout);
212 if (extract_cached(fname)) {
213 verbose_msg("Could not create %s file, create tmp file\n",
214 ZIOREP_CONFIG_EXT);
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);
220 return -1;
224 fprintf(stdout, "done\n");
226 verbose_msg("Check config data finished\n");
228 return 0;
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)
237 + 1);
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
244 remove(m_tmp_file);
245 free(m_tmp_file);
246 m_tmp_file = NULL;
247 return -1;
249 m_cfg_cached = true;
251 return 0;
255 int ConfigReader::extract_tmp(const char *fname)
257 int rc = 0;
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));
267 rc = -1;
268 goto out;
271 rc = extract(fname);
273 out:
274 if (rc) {
275 free(m_tmp_file);
276 m_tmp_file = NULL;
279 return rc;
283 int ConfigReader::extract(const char *fname)
285 int rc = 0;
286 char *cmd = NULL;
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)
291 + 12 + 1);
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);
298 if (system(cmd)) {
299 rc = -1;
300 goto out;
302 verbose_msg("Data extracted to %s\n", m_tmp_file);
304 out:
305 free(cmd);
306 return rc;
310 bool ConfigReader::cached_config_exists(const char *fname)
312 int rc = true;
314 m_tmp_file = (char*)malloc(strlen(fname) + strlen(ZIOREP_CONFIG_EXT)
315 + 1);
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");
320 free(m_tmp_file);
321 m_tmp_file = NULL;
322 rc = false;
325 return rc;
329 int ConfigReader::extract_adapter_info_sub(char **tgt, char *p, char delim)
331 int offset;
333 offset = get_index_to(p, delim);
334 if (offset <=0)
335 return -1;
336 *tgt = (char*)malloc(offset + 1);
337 strncpy(*tgt, p, offset);
338 (*tgt)[offset] = '\0';
340 return 0;
344 void ConfigReader::init_device_info(struct device_info *info)
346 info->multipath_device = NULL;
347 info->device = NULL;
348 info->type = NULL;
352 void ConfigReader::free_device_info(struct device_info *info)
354 free(info->multipath_device);
355 info->multipath_device = NULL;
356 free(info->device);
357 info->device = NULL;
358 free(info->type);
359 info->type = NULL;
363 int ConfigReader::get_index_to(char *p, char c) const
365 int i;
367 for (i = 0; *p != c && *p != '\0'; ++p, ++i) ;
369 return i;
373 void ConfigReader::host_id_not_found_error(__u32 h, int *rc) const
375 *rc = -1;
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
384 *rc = -1;
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
393 *rc = -1;
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
402 *rc = -1;
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
411 *rc = -1;
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
421 *rc = -1;
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
430 *rc = -1;
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
439 *rc = -1;
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
448 *rc = -1;
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) \
458 return (*i).ret; \
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) \
464 return (*i).ret; \
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);
473 return 0;
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);
483 return 0;
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);
493 return 0;
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);
503 return 0;
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);
513 return 0;
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);
523 return 0;
527 __u32 ConfigReader::get_devno_by_ident(const struct hctl_ident *ident,
528 int *rc) const
530 search_for_by_dev(ident, devno);
532 ident_not_found_error(ident, rc);
534 return 0;
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);
544 return 0;
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/"),
554 mp) == 0)
555 return (*i).mp_mm;
558 mp_not_found_error(mp, rc);
560 return 0;
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);
570 return NULL;
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);
580 return 0;
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);
590 return 0;
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);
600 return 0;
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);
610 return 0;
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);
620 return 0;
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);
638 return 0;
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);
651 return 0;
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);
664 return NULL;
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
704 mp_mms.clear();
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
720 lst.clear();
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
730 idents.clear();
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
741 devnos.clear();
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
752 devnos.clear();
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) \
797 return true; \
799 return false;
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) \
806 rc = true; \
810 bool ConfigReader::verify_chpid(__u32 c) const
812 verify_numeric(chpid, c);
816 bool ConfigReader::verify_device(const char *dev) const
818 bool rc = false;
819 char *tmp;
821 tmp = (char*)malloc(strlen(dev) + strlen("/dev/") + 1);
822 sprintf(tmp, "/dev/%s", dev);
824 verify_char(device, tmp, rc);
826 free(tmp);
828 return rc;
832 bool ConfigReader::verify_mp_device(const char *mp) const
834 bool rc = false;
835 char *tmp;
837 tmp = (char*)malloc(strlen(mp) + strlen("/dev/mapper/") + 1);
838 sprintf(tmp, "/dev/mapper/%s", mp);
840 verify_char(multipath_device, tmp, rc);
842 free(tmp);
844 return 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,
883 (*i).type);