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