1 /*
2  * Copyright © 2013-2021 Inria.  All rights reserved.
3  * See COPYING in top-level directory.
4  */
5 
6 #include "private/autogen/config.h"
7 #include "hwloc.h"
8 #include "hwloc/diff.h"
9 #include "misc.h"
10 
usage(const char * callname __hwloc_attribute_unused,FILE * where)11 void usage(const char *callname __hwloc_attribute_unused, FILE *where)
12 {
13 	fprintf(where, "Usage: hwloc-patch [options] [<old.xml> | refname] [<diff.xml> | -] [<output.xml>]\n");
14 	fprintf(where, "Options:\n");
15 	fprintf(where, "  -R --reverse     Reverse the sense of the difference\n");
16 	fprintf(where, "  --version        Report version and exit\n");
17         fprintf(where, "  -h --help        Show this usage\n");
18 }
19 
hwloc_diff_read(const char * inputdiff,hwloc_topology_diff_t * firstdiffp,char ** refnamep)20 static int hwloc_diff_read(const char *inputdiff,
21 			   hwloc_topology_diff_t *firstdiffp, char **refnamep)
22 {
23 	size_t buflen, offset, readlen;
24 	char *buffer, *tmp;
25 	size_t ret;
26 	int err;
27 
28 	if (strcmp(inputdiff, "-"))
29 		return hwloc_topology_diff_load_xml(inputdiff, firstdiffp, refnamep);
30 
31 	buflen = 4096;
32 	buffer = malloc(buflen+1); /* one more byte for the ending \0 */
33 	if (!buffer)
34 		goto out;
35 
36 	offset = 0; readlen = buflen;
37 	while (1) {
38 		ret = fread(buffer+offset, 1, readlen, stdin);
39 
40 		offset += ret;
41 		buffer[offset] = 0;
42 
43 		if (ret != readlen)
44 			break;
45 
46 		buflen *= 2;
47 		tmp = realloc(buffer, buflen+1);
48 		if (!tmp) {
49 			fprintf(stderr, "Failed to realloc buffer for reading diff.\n");
50 			goto out_with_buffer;
51 		}
52 		buffer = tmp;
53 		readlen = buflen/2;
54 	}
55 
56 	err = hwloc_topology_diff_load_xmlbuffer(buffer, (int)(offset+1), firstdiffp, refnamep);
57 	free(buffer);
58 	return err;
59 
60 out_with_buffer:
61 	free(buffer);
62 out:
63 	return -1;
64 }
65 
main(int argc,char * argv[])66 int main(int argc, char *argv[])
67 {
68 	hwloc_topology_t topo;
69 	hwloc_topology_diff_t firstdiff = NULL;
70 	unsigned long flags = HWLOC_TOPOLOGY_FLAG_INCLUDE_DISALLOWED | HWLOC_TOPOLOGY_FLAG_IMPORT_SUPPORT;
71 	unsigned long patchflags = 0;
72 	char *callname, *input, *inputdiff, *output = NULL, *refname = NULL;
73 	int err;
74 
75         callname = strrchr(argv[0], '/');
76         if (!callname)
77           callname = argv[0];
78         else
79           callname++;
80 
81 	/* skip argv[0], handle options */
82 	argc--;
83 	argv++;
84 
85 	hwloc_utils_check_api_version(callname);
86 
87 	if (!getenv("HWLOC_XML_VERBOSE"))
88 		putenv((char *) "HWLOC_XML_VERBOSE=1");
89 
90 	while (argc && *argv[0] == '-') {
91 		if (!strcmp (argv[0], "-R") || !strcmp (argv[0], "--reverse")) {
92 			patchflags ^= HWLOC_TOPOLOGY_DIFF_APPLY_REVERSE;
93 		} else if (!strcmp (argv[0], "--version")) {
94 			printf("%s %s\n", callname, HWLOC_VERSION);
95 			exit(EXIT_SUCCESS);
96 		} else if (!strcmp(argv[0], "-h") || !strcmp(argv[0], "--help")) {
97 			usage(callname, stdout);
98 			exit(EXIT_SUCCESS);
99 		} else {
100 			fprintf(stderr, "Unrecognized options: %s\n", argv[0]);
101 			usage(callname, stderr);
102 			exit(EXIT_FAILURE);
103 		}
104 		argc--;
105 		argv++;
106 	}
107 
108 	if (argc < 2) {
109 		usage(callname, stderr);
110 		exit(EXIT_FAILURE);
111 	}
112 	input = argv[0];
113 	inputdiff = argv[1];
114 	argc -= 2;
115 	argv += 2;
116 	if (argc >= 1) {
117 		output = argv[0];
118 		argc--;
119 		argv++;
120 	}
121 
122 	/* load the diff and get the refname */
123 	err = hwloc_diff_read(inputdiff, &firstdiff, &refname);
124 	if (err < 0) {
125 		fprintf(stderr, "Failed to load XML topology diff %s\n", inputdiff);
126 		goto out;
127 	}
128 
129 	/* load the input topology */
130 	hwloc_topology_init(&topo);
131 	hwloc_topology_set_all_types_filter(topo, HWLOC_TYPE_FILTER_KEEP_ALL);
132 	hwloc_topology_set_flags(topo, flags);
133 	if (!strcmp(input, "refname")) {
134 		/* use the diff refname as input */
135 		if (!refname) {
136 			fprintf(stderr, "Couldn't find the reference topology name from the input diff %s\n", inputdiff);
137 			goto out_with_topo;
138 		}
139 		err = hwloc_topology_set_xml(topo, refname);
140 		if (err < 0) {
141 			fprintf(stderr, "Failed to load XML topology %s (from input diff %s refname)\n", refname, inputdiff);
142 			goto out_with_topo;
143 		}
144 	} else {
145 		/* use the given input */
146 		err = hwloc_topology_set_xml(topo, input);
147 		if (err < 0) {
148 			fprintf(stderr, "Failed to load XML topology %s\n", input);
149 			goto out_with_topo;
150 		}
151 	}
152 
153 	err = hwloc_topology_load(topo);
154 	if (err < 0) {
155 		fprintf(stderr, "Failed to load topology\n");
156 		goto out_with_topo;
157 	}
158 
159 	err = hwloc_topology_diff_apply(topo, firstdiff, patchflags);
160 	if (err < 0) {
161 		fprintf(stderr, "Failed to%s apply topology diff %s, failed for hunk #%d hunk\n",
162 			(patchflags & HWLOC_TOPOLOGY_DIFF_APPLY_REVERSE) ? " reverse" : "",
163 			inputdiff, -err);
164 		goto out_with_topo;
165 	}
166 
167 	err = hwloc_topology_export_xml(topo, output ? output : input, 0);
168 	if (err < 0) {
169 		fprintf(stderr, "Failed to export patched topology %s\n", output);
170 		goto out_with_topo;
171 	}
172 
173 	hwloc_topology_destroy(topo);
174 	hwloc_topology_diff_destroy(firstdiff);
175 
176 	exit(EXIT_SUCCESS);
177 
178 out_with_topo:
179 	hwloc_topology_destroy(topo);
180 	hwloc_topology_diff_destroy(firstdiff);
181 out:
182 	exit(EXIT_FAILURE);
183 }
184