Mercurial > illumos > onarm
annotate usr/src/cmd/abi/spectrans/spec2map/xlator.c @ 4:1a15d5aaf794
synchronized with onnv_86 (6202) in onnv-gate
author | Koji Uno <koji.uno@sun.com> |
---|---|
date | Mon, 31 Aug 2009 14:38:03 +0900 |
parents | c9caec207d52 |
children |
rev | line source |
---|---|
0 | 1 /* |
2 * CDDL HEADER START | |
3 * | |
4 * The contents of this file are subject to the terms of the | |
5 * Common Development and Distribution License, Version 1.0 only | |
6 * (the "License"). You may not use this file except in compliance | |
7 * with the License. | |
8 * | |
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE | |
10 * or http://www.opensolaris.org/os/licensing. | |
11 * See the License for the specific language governing permissions | |
12 * and limitations under the License. | |
13 * | |
14 * When distributing Covered Code, include this CDDL HEADER in each | |
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. | |
16 * If applicable, add the following below this CDDL HEADER, with the | |
17 * fields enclosed by brackets "[]" replaced with your own identifying | |
18 * information: Portions Copyright [yyyy] [name of copyright owner] | |
19 * | |
20 * CDDL HEADER END | |
21 */ | |
22 /* | |
23 * Copyright 2003 Sun Microsystems, Inc. All rights reserved. | |
24 * Use is subject to license terms. | |
25 */ | |
26 | |
4
1a15d5aaf794
synchronized with onnv_86 (6202) in onnv-gate
Koji Uno <koji.uno@sun.com>
parents:
0
diff
changeset
|
27 #pragma ident "%Z%%M% %I% %E% SMI" |
0 | 28 |
29 /* | |
30 * Back-end functions for spec to mapfile converter | |
31 */ | |
32 | |
33 #include <stdio.h> | |
34 #include <stdlib.h> | |
35 #include <ctype.h> | |
36 #include <string.h> | |
37 #include <errno.h> | |
38 #include <sys/utsname.h> | |
39 #include "xlator.h" | |
40 #include "util.h" | |
41 #include "bucket.h" | |
42 | |
43 /* Globals */ | |
44 enum { | |
45 /* These first four (commented out) are defined in parser.h */ | |
46 /* XLATOR_KW_NOTFOUND = 0, */ | |
47 /* XLATOR_KW_FUNC, */ | |
48 /* XLATOR_KW_DATA, */ | |
49 /* XLATOR_KW_END, */ | |
50 XLATOR_KW_VERSION = 4, | |
51 XLATOR_KW_ARCH, | |
52 XLATOR_KW_BINDING, | |
53 XLATOR_KW_FILTER, | |
54 XLATOR_KW_AUXILIARY | |
55 }; | |
56 #define FIRST_TOKEN 4 /* Must match the first token in the enum above */ | |
57 | |
58 static xlator_keyword_t Keywords[] = { | |
59 { "version", XLATOR_KW_VERSION }, | |
60 { "arch", XLATOR_KW_ARCH }, | |
61 { "binding", XLATOR_KW_BINDING }, | |
62 { "filter", XLATOR_KW_FILTER }, | |
63 { "auxiliary", XLATOR_KW_AUXILIARY }, | |
64 { NULL, XLATOR_KW_NOTFOUND } | |
65 }; | |
66 | |
67 static char const *OutputFile; | |
68 static char const *Curfile; | |
69 static char *Curfun; | |
70 static int Curline; | |
71 static Interface Iface; | |
72 | |
73 static int Verbosity; | |
74 static int TargetArchToken; /* set from -a option to front-end */ | |
75 char *TargetArchStr = NULL; /* from -a option to front-end */ | |
76 int IsFilterLib = 0; /* set from -F option to front-end */ | |
77 static int Supported_Arch = XLATOR_ALLARCH; /* from "Arch" SPEC keyword */ | |
78 static int Flags; | |
79 | |
80 /* | |
81 * WHAT!? | |
82 * from Version line | |
83 * 0 means architecture is not specified in the | |
84 * version line so it applies to all versions | |
85 */ | |
86 static int Version_Arch; | |
87 int Num_versfiles = 0; | |
88 static int Has_Version; | |
89 | |
90 static char *Versfile; | |
91 | |
92 static char *getversion(const char *); | |
93 static int version_sanity(const char *value, char **subv); | |
94 static int arch_version_sanity(char *av); | |
95 static char *getfilter(const char *); | |
96 static void writemapfile(FILE *); | |
97 static int set_version_arch(const char *); | |
98 static int set_supported_arch(const char *); | |
99 | |
100 /* | |
101 * xlator_init() | |
102 * back-end initialization | |
103 * returns pointer to Keywords on success | |
104 * returns NULL pointer on failure | |
105 */ | |
106 xlator_keyword_t * | |
107 xlator_init(const Translator_info *t_info) | |
108 { | |
109 /* | |
110 * initially so we don't lose error messages from version_check | |
111 * we'll set this again later based on ti_info.ti_verbosity | |
112 */ | |
113 seterrseverity(WARNING); | |
114 | |
115 /* set verbosity */ | |
116 Verbosity = t_info->ti_verbosity; | |
117 seterrseverity(t_info->ti_verbosity); | |
118 | |
119 /* Obtain translator flags */ | |
120 Flags = t_info->ti_flags; | |
121 | |
122 /* | |
123 * set Library Type | |
124 * 1 if filter lib, 0 otherwise | |
125 */ | |
126 IsFilterLib = t_info->ti_libtype; | |
127 | |
128 /* set target architecture */ | |
129 TargetArchStr = t_info->ti_arch; | |
130 TargetArchToken = t_info->ti_archtoken; | |
131 | |
132 errlog(STATUS, "Architecture set to \"%s\"", TargetArchStr); | |
133 | |
134 /* set output file */ | |
135 OutputFile = t_info->ti_output_file; | |
136 if (OutputFile) { | |
137 errlog(STATUS, "Output will go into %s", | |
138 OutputFile); | |
139 } else { | |
140 OutputFile = "mapfile"; | |
141 errlog(STATUS, "Using default output filename: %s", | |
142 OutputFile); | |
143 } | |
144 | |
145 /* obtain name of version file */ | |
146 Versfile = t_info->ti_versfile; | |
147 | |
148 /* call create_lists() to setup for parse_versions() */ | |
149 create_lists(); | |
150 | |
151 /* Process Vers Files */ | |
152 if (parse_versions(Versfile)) { | |
153 return (NULL); | |
154 } | |
155 | |
156 return (Keywords); | |
157 } | |
158 | |
159 /* | |
160 * xlator_startlib() | |
161 * start of library | |
162 * returns: XLATOR_SUCCESS on success | |
163 * XLATOR_SKIP if library is to be skipped | |
164 * XLATOR_NONFATAL on error | |
165 */ | |
166 /*ARGSUSED*/ | |
167 int | |
168 xlator_startlib(char const *libname) | |
169 { | |
170 errlog(TRACING, "xlator_startlib"); | |
171 return (XLATOR_SUCCESS); | |
172 } | |
173 | |
174 /* | |
175 * xlator_startfile() | |
176 * start of spec file | |
177 * returns: XLATOR_SUCCESS on success | |
178 * XLATOR_SKIP if file is to be skipped | |
179 * XLATOR_NONFATAL on error | |
180 */ | |
181 int | |
182 xlator_startfile(char const *filename) | |
183 { | |
184 errlog(TRACING, "xlator_startfile"); | |
185 | |
186 Curfile = filename; | |
187 | |
188 return (XLATOR_SUCCESS); | |
189 } | |
190 | |
191 /* | |
192 * xlator_start_if () | |
193 * start of interface specification | |
194 * returns: XLATOR_SUCCESS on success | |
195 * XLATOR_SKIP if interface is to be skipped | |
196 * XLATOR_NONFATAL on error | |
197 * XLATOR_FATAL on fatal error | |
198 */ | |
199 int | |
200 xlator_start_if(const Meta_info meta_info, const int token, char *value) | |
201 { | |
202 char rhs[BUFSIZ]; | |
203 char *kw; | |
204 int err; | |
205 | |
206 errlog(TRACING, "xlator_start_if %s", value); | |
207 | |
208 switch (token) { | |
209 case XLATOR_KW_FUNC: | |
210 kw = "Function"; | |
211 break; | |
212 case XLATOR_KW_DATA: | |
213 kw = "Data"; | |
214 break; | |
215 default: | |
216 /* This should never happen */ | |
217 errlog(ERROR, | |
218 "\"%s\", line %d: Implementation error! " | |
219 "Please file a bug\n", __FILE__, __LINE__); | |
220 return (XLATOR_FATAL); | |
221 } | |
222 | |
223 Curline = meta_info.mi_line_number; | |
224 seterrline(Curline, meta_info.mi_filename, kw, value); | |
225 | |
226 if (Curfun != NULL) { | |
227 errlog(INPUT|ERROR, | |
228 "Error: Interface spec is missing the " | |
229 "End keyword: %s", Curfun); | |
230 return (XLATOR_NONFATAL); | |
231 } | |
232 | |
233 err = sscanf(value, "%s", rhs); | |
234 if (err == 0 || err == EOF) { | |
235 errlog(INPUT|ERROR, | |
236 "Error: Missing argument in \"%s\" line", kw); | |
237 return (XLATOR_NONFATAL); | |
238 } | |
239 | |
240 Curfun = strdup(rhs); | |
241 | |
242 if (Curfun == NULL) { | |
243 errlog(ERROR | FATAL, | |
244 "Internal Error: strdup() failure in xlator_startif()"); | |
245 } | |
246 | |
247 Iface.IF_name = Curfun; | |
248 Iface.IF_type = token; /* FUNCTION or DATA */ | |
249 | |
250 Iface.IF_version = NULL; | |
251 Iface.IF_class = NULL; | |
252 Has_Version = 0; | |
253 Supported_Arch = XLATOR_ALLARCH; | |
254 Version_Arch = 0; | |
255 | |
256 Iface.IF_binding = DEFAULT; | |
257 | |
258 Iface.IF_filter = NULL; | |
259 Iface.IF_auxiliary = NULL; | |
260 | |
261 return (XLATOR_SUCCESS); | |
262 } | |
263 | |
264 /* | |
265 * xlator_take_kvpair() | |
266 * processes spec keyword-value pairs | |
267 * returns: XLATOR_SUCCESS on success | |
268 * XLATOR_NONFATAL on error | |
269 */ | |
270 int | |
271 xlator_take_kvpair(const Meta_info meta_info, const int token, | |
272 char *value) | |
273 { | |
274 char *p; | |
275 char *subv = NULL; | |
276 char *key = Keywords[token-FIRST_TOKEN].key; | |
277 | |
278 Curline = meta_info.mi_line_number; | |
279 seterrline(Curline, meta_info.mi_filename, key, value); | |
280 | |
281 errlog(TRACING, | |
282 "take_kvpair called. ext_cnt=%d token=%d key=%s value=%s", | |
283 meta_info.mi_ext_cnt, token, key, value); | |
284 | |
285 if (Curfun == NULL) { | |
286 errlog(INPUT|ERROR, "Error: Keyword found outside " | |
287 "an interface specification block, line %d", Curline); | |
288 return (XLATOR_NONFATAL); | |
289 } | |
290 | |
291 switch (token) { | |
292 case XLATOR_KW_VERSION: | |
293 if (meta_info.mi_ext_cnt != 0) | |
294 return (XLATOR_SUCCESS); | |
295 | |
296 errlog(TRACING, "Version found. Setting Version to %s", value); | |
297 | |
298 /* Version line found ; used for auditing the SPEC */ | |
299 Has_Version = 1; | |
300 | |
301 /* remove trailing white space */ | |
302 p = strrchr(value, '\n'); | |
303 if (p) { | |
304 while (p >= value && isspace(*p)) { | |
305 *p = '\0'; | |
306 --p; | |
307 } | |
308 } | |
309 | |
310 /* is the version line valid */ | |
311 switch (version_sanity(value, &subv)) { | |
312 case VS_OK: /* OK, subv not set */ | |
313 break; | |
314 | |
315 case VS_INVARCH: /* Invalid Arch */ | |
316 errlog(INPUT|ERROR, "Error: Invalid architecture " | |
317 "string found in spec or version file: %s", subv); | |
318 free(subv); | |
319 return (XLATOR_NONFATAL); | |
320 | |
321 case VS_INVVERS: /* Invalid Version String */ | |
322 errlog(INPUT|ERROR, "Error: Invalid version string " | |
323 "in spec or version file: %s", subv); | |
324 free(subv); | |
325 return (XLATOR_NONFATAL); | |
326 | |
327 case VS_INVALID: /* Both Version and Arch are invalid */ | |
328 errlog(INPUT|ERROR, "Error: Invalid version and " | |
329 "architecture string in spec or version file" | |
330 ": %s", subv); | |
331 free(subv); | |
332 return (XLATOR_NONFATAL); | |
333 | |
334 default: /* BAD IMPLEMENTATION OF version_sanity */ | |
335 errlog(FATAL, "Error: bad return value from " | |
336 "version_sanity()! This should never happen!"); | |
337 } | |
338 | |
339 errlog(TRACING, "Version_Arch=%d", Version_Arch); | |
340 | |
341 Iface.IF_version = getversion(value); | |
342 break; | |
343 | |
344 case XLATOR_KW_ARCH: | |
345 if (meta_info.mi_ext_cnt != 0) | |
346 return (XLATOR_SUCCESS); | |
347 | |
348 if (value[0] != '\0') { | |
349 Supported_Arch = 0; | |
350 if (set_supported_arch(value)) { | |
351 errlog(INPUT|ERROR, | |
352 "Error: Unable to parse Arch line"); | |
353 return (XLATOR_NONFATAL); | |
354 } | |
355 } else { | |
356 errlog(INPUT | ERROR, "Error: Empty Arch line."); | |
357 } | |
358 | |
359 if (Supported_Arch == 0) { | |
360 errlog(INPUT | ERROR, | |
361 "Error: Unknown architecture defined in Arch line"); | |
362 } | |
363 | |
364 errlog(TRACING, | |
365 "Interface %s supports the following architectures: " | |
366 "%s\tSupported_Arch=%d", Curfun, value, Supported_Arch); | |
367 break; | |
368 | |
369 case XLATOR_KW_BINDING: | |
370 | |
371 /* | |
372 * Note that we allow extends for the binding keyword by | |
373 * not checking that meta_info.mi_ext_cnt == 0 here. | |
374 */ | |
375 | |
376 /* remove trailing white space */ | |
377 p = strrchr(value, '\n'); | |
378 if (p) { | |
379 while (p >= value && isspace(*p)) { | |
380 *p = '\0'; | |
381 --p; | |
382 } | |
383 } | |
384 | |
385 if (value[0] != '\0') { | |
386 if (strcmp(value, "direct") == 0) { | |
387 Iface.IF_binding = DIRECT; | |
388 } else if (strcmp(value, "nodirect") == 0) { | |
389 Iface.IF_binding = NODIRECT; | |
390 } else if (strcmp(value, "protected") == 0) { | |
391 Iface.IF_binding = PROTECTED; | |
392 } else { | |
393 errlog(INPUT|ERROR, | |
394 "Error: Invalid binding value: %s", value); | |
395 } | |
396 } else { | |
397 errlog(INPUT | ERROR, "Error: Empty Binding line."); | |
398 } | |
399 | |
400 errlog(TRACING, | |
401 "Interface %s has binding value: " | |
402 "%s", Curfun, value); | |
403 break; | |
404 | |
405 case XLATOR_KW_FILTER: | |
406 case XLATOR_KW_AUXILIARY: | |
407 /* | |
408 * The following is for the "extends" clause. As with | |
409 * XLATOR_KW_VERSION, we do not want to follow an "extends" | |
410 * chain to get the filter or auxiliary values: we want | |
411 * the first/most-tightly-bound one (mi_ext_cnt = 0). | |
412 */ | |
413 if (meta_info.mi_ext_cnt != 0) | |
414 return (XLATOR_SUCCESS); | |
415 | |
416 errlog(TRACING, "Filter[token=%d] found. Setting Filter to %s", | |
417 token, value); | |
418 | |
419 /* remove trailing white space */ | |
420 p = strrchr(value, '\n'); | |
421 if (p) { | |
422 while (p >= value && isspace(*p)) { | |
423 *p = '\0'; | |
424 --p; | |
425 } | |
426 } | |
427 | |
428 errlog(TRACING, "Version_Arch=%d", Version_Arch); | |
429 | |
430 if (token == XLATOR_KW_FILTER) { | |
431 Iface.IF_filter = getfilter(value); | |
432 } else if (token == XLATOR_KW_AUXILIARY) { | |
433 Iface.IF_auxiliary = getfilter(value); | |
434 } | |
435 | |
436 break; | |
437 default: | |
438 errlog(INPUT|ERROR, "Error: Unrecognized keyword snuck in!" | |
439 "\tThis is a programmer error: %s", key); | |
440 return (XLATOR_NONFATAL); | |
441 } | |
442 | |
443 return (XLATOR_SUCCESS); | |
444 } | |
445 | |
446 /* | |
447 * xlator_end_if () | |
448 * signal end of spec interface spec | |
449 * returns: XLATOR_SUCCESS on success | |
450 * XLATOR_NONFATAL on error | |
451 */ | |
452 /*ARGSUSED*/ | |
453 int | |
454 xlator_end_if(const Meta_info M, const char *value) | |
455 { | |
456 int retval = XLATOR_NONFATAL; | |
457 int picky = Flags & XLATOR_PICKY_FLAG; | |
458 | |
459 seterrline(M.mi_line_number, M.mi_filename, "End", ""); | |
460 errlog(TRACING, "xlator_end_if"); | |
461 | |
462 if (Curfun == NULL) { | |
463 errlog(INPUT | ERROR, "Error: End without " | |
464 "matching Function or Data in file \"%s\"", Curfile); | |
465 goto cleanup; | |
466 } | |
467 | |
468 errlog(TRACING, "Interface=%s", Iface.IF_name); | |
469 | |
470 if (!Has_Version) { | |
471 if (picky) { | |
472 errlog(INPUT | ERROR, "Error: Interface has no " | |
473 "Version!\n\tInterface=%s\n\tSPEC File=%s", | |
474 Iface.IF_name, Curfile); | |
475 } else { | |
476 errlog(INPUT | WARNING, "Warning: Interface has " | |
477 "no Version!\n\tInterface=%s\n\tSPEC File=%s", | |
478 Iface.IF_name, Curfile); | |
479 retval = XLATOR_SUCCESS; | |
480 } | |
481 goto cleanup; | |
482 } | |
483 | |
484 if (Version_Arch & (~Supported_Arch)) { | |
485 errlog(INPUT | ERROR, "Error: Architectures in Version " | |
486 "line must be a subset of Architectures in Arch line\n" | |
487 "\tInterface=%s\n\tSPEC File=%s", Iface.IF_name, Curfile); | |
488 goto cleanup; | |
489 } | |
490 | |
491 if ((TargetArchToken & Supported_Arch) == 0) { | |
492 /* | |
493 * This interface is not for the architecture | |
494 * we are currently processing, so we skip it. | |
495 */ | |
496 retval = XLATOR_SUCCESS; | |
497 goto cleanup; | |
498 } | |
499 | |
500 if (Iface.IF_version == NULL) { | |
501 if (picky) { | |
502 errlog(ERROR|INPUT, | |
503 "Error: Version was not found for " | |
504 "\"%s\" architecture\n\tInterface=%s", | |
505 TargetArchStr, Iface.IF_name); | |
506 } else { | |
507 errlog(WARNING | INPUT, | |
508 "Warning: Version was not found for " | |
509 "\"%s\" architecture\n\tInterface=%s", | |
510 TargetArchStr, Iface.IF_name); | |
511 retval = XLATOR_SUCCESS; | |
512 } | |
513 goto cleanup; | |
514 } | |
515 | |
516 /* check Iface.IF_type */ | |
517 switch (Iface.IF_type) { | |
518 case FUNCTION: | |
519 errlog(VERBOSE, "Interface type = FUNCTION"); | |
520 break; | |
521 case DATA: | |
522 errlog(VERBOSE, "Interface type = DATA"); | |
523 break; | |
524 case NOTYPE: | |
525 errlog(WARNING, | |
526 "Warning: Interface is neither " | |
527 "DATA nor FUNCTION!!\n\t" | |
528 "Interface=%s\n\tSPEC File=%s", | |
529 Iface.IF_name, Curfile); | |
530 break; | |
531 default: | |
532 errlog(ERROR, "Error: Bad spec2map implementation!\n" | |
533 "\tInterface type is invalid\n" | |
534 "\tThis should never happen.\n" | |
535 "\tInterface=%s\tSPEC File=%s", Iface.IF_name, Curfile); | |
536 goto cleanup; | |
537 } | |
538 | |
539 (void) add_by_name(Iface.IF_version, &Iface); | |
540 | |
541 retval = XLATOR_SUCCESS; | |
542 | |
543 cleanup: | |
544 | |
545 /* cleanup */ | |
546 Iface.IF_name = NULL; | |
547 | |
548 free(Iface.IF_version); | |
549 Iface.IF_version = NULL; | |
550 | |
551 free(Iface.IF_class); | |
552 Iface.IF_class = NULL; | |
553 | |
554 free(Curfun); | |
555 Curfun = NULL; | |
556 | |
557 Supported_Arch = XLATOR_ALLARCH; | |
558 return (retval); | |
559 } | |
560 | |
561 /* | |
562 * xlator_endfile() | |
563 * signal end of spec file | |
564 * returns: XLATOR_SUCCESS on success | |
565 * XLATOR_NONFATAL on error | |
566 */ | |
567 int | |
568 xlator_endfile(void) | |
569 { | |
570 | |
571 errlog(TRACING, "xlator_endfile"); | |
572 | |
573 Curfile = NULL; | |
574 | |
575 return (XLATOR_SUCCESS); | |
576 } | |
577 | |
578 /* | |
579 * xlator_endlib() | |
580 * signal end of library | |
581 * returns: XLATOR_SUCCESS on success | |
582 * XLATOR_NONFATAL on error | |
583 */ | |
584 int | |
585 xlator_endlib(void) | |
586 { | |
587 FILE *mapfp; | |
588 int retval = XLATOR_SUCCESS; | |
589 | |
590 errlog(TRACING, "xlator_endlib"); | |
591 | |
592 /* Pretend to print mapfile */ | |
593 if (Verbosity >= TRACING) { | |
594 print_all_buckets(); | |
595 } | |
596 | |
597 /* Everything read, now organize it! */ | |
598 sort_buckets(); | |
599 add_local(); | |
600 | |
601 /* Create Output */ | |
602 mapfp = fopen(OutputFile, "w"); | |
603 if (mapfp == NULL) { | |
604 errlog(ERROR, | |
605 "Error: Unable to open output file \"%s\"\n\t%s", | |
606 OutputFile, strerror(errno)); | |
607 retval = XLATOR_NONFATAL; | |
608 } else { | |
609 writemapfile(mapfp); | |
610 (void) fclose(mapfp); | |
611 } | |
612 | |
613 return (retval); | |
614 } | |
615 | |
616 /* | |
617 * xlator_end() | |
618 * signal end of translation | |
619 * returns: XLATOR_SUCCESS on success | |
620 * XLATOR_NONFATAL on error | |
621 */ | |
622 int | |
623 xlator_end(void) | |
624 { | |
625 errlog(TRACING, "xlator_end"); | |
626 | |
627 /* Destroy the list created by create_lists */ | |
628 delete_lists(); | |
629 | |
630 return (XLATOR_SUCCESS); | |
631 } | |
632 | |
633 /* | |
634 * getversion() | |
635 * called by xlator_take_kvpair when Version keyword is found | |
636 * parses the Version string and returns the one that matches | |
637 * the current target architecture | |
638 * | |
639 * the pointer returned by this function must be freed later. | |
640 */ | |
641 static char * | |
642 getversion(const char *value) | |
643 { | |
644 char *v, *p; | |
645 char arch[ARCHBUFLEN]; | |
646 int archlen; | |
647 | |
648 /* up to ARCHBUFLEN-1 */ | |
649 (void) strncpy(arch, TargetArchStr, ARCHBUFLEN-1); | |
650 arch[ARCHBUFLEN-2] = '\0'; | |
651 (void) strcat(arch, "="); /* append an '=' */ | |
652 archlen = strlen(arch); | |
653 | |
654 errlog(VERBOSE, "getversion: value=%s", value); | |
655 | |
656 if (strchr(value, '=') != NULL) { | |
657 if ((v = strstr(value, arch)) != NULL) { | |
658 p = strdup(v + archlen); | |
659 if (p == NULL) { | |
660 errlog(ERROR | FATAL, | |
661 "Internal Error: strdup() failure " | |
662 "in getversion()"); | |
663 } | |
664 v = p; | |
665 while (!isspace(*v) && *v != '\0') | |
666 ++v; | |
667 *v = '\0'; | |
668 } else { | |
669 errlog(VERBOSE, "getversion returns: NULL"); | |
670 return (NULL); | |
671 } | |
672 } else { | |
673 p = strdup(value); | |
674 if (p == NULL) { | |
675 errlog(ERROR | FATAL, "Internal Error: strdup() " | |
676 "failure in getversion()"); | |
677 } | |
678 } | |
679 | |
680 if (p != NULL) | |
681 errlog(VERBOSE, "getversion returns: %s", p); | |
682 else | |
683 errlog(VERBOSE, "getversion returns: NULL"); | |
684 | |
685 return (p); | |
686 } | |
687 | |
688 /* | |
689 * getfilter() | |
690 * Called by xlator_take_kvpair when "filter" or "auxiliary" keyword is | |
691 * found. Parses the Filter/Auxiliary string and returns the one that | |
692 * matches the current target architecture | |
693 * | |
694 * The pointer returned by this function must be freed later. | |
695 * | |
696 * Note that returning NULL here indicates there was no desired | |
697 * arch=path item in value, i.e. for TargetArchStr the interface is | |
698 * not a filter. | |
699 */ | |
700 static char * | |
701 getfilter(const char *value) | |
702 { | |
703 char *v, *p; | |
704 char arch[ARCHBUFLEN]; | |
705 int archlen; | |
706 | |
707 /* up to ARCHBUFLEN-1 */ | |
708 (void) strncpy(arch, TargetArchStr, ARCHBUFLEN-1); | |
709 arch[ARCHBUFLEN-2] = '\0'; | |
710 (void) strcat(arch, "="); /* append an '=' */ | |
711 archlen = strlen(arch); | |
712 | |
713 errlog(VERBOSE, "getfilter: value=%s", value); | |
714 | |
715 if (strchr(value, '=') != NULL) { | |
716 if ((v = strstr(value, arch)) != NULL) { | |
717 p = strdup(v + archlen); | |
718 if (p == NULL) { | |
719 errlog(ERROR | FATAL, | |
720 "Internal Error: strdup() failure " | |
721 "in getfilter()"); | |
722 } | |
723 v = p; | |
724 while (!isspace(*v) && *v != '\0') | |
725 ++v; | |
726 *v = '\0'; | |
727 } else { | |
728 errlog(VERBOSE, "getfilter returns: NULL"); | |
729 return (NULL); | |
730 } | |
731 } else { | |
732 p = strdup(value); | |
733 if (p == NULL) { | |
734 errlog(ERROR | FATAL, "Internal Error: strdup() " | |
735 "failure in getfilter()"); | |
736 } | |
737 } | |
738 | |
739 if (p != NULL) | |
740 errlog(VERBOSE, "getfilter returns: %s", p); | |
741 else | |
742 errlog(VERBOSE, "getfilter returns: NULL"); | |
743 | |
744 return (p); | |
745 } | |
746 | |
747 /* | |
748 * version_sanity() | |
749 * for each version info in the Version line | |
750 * check for its validity. | |
751 * Set Version_arch to reflect all supported architectures if successful. | |
752 * Upon return on failure, subv will contain the last version string | |
753 * processed | |
754 * returns: VS_OK OK | |
755 * VS_INVARCH Invalid Architecture | |
756 * VS_INVVERS Invalid Version String | |
757 * VS_INVALID Both Version and Architecture are invalid; | |
758 */ | |
759 static int | |
760 version_sanity(const char *value, char **subv) | |
761 { | |
762 char *p, *v, *a; | |
763 int retval = VS_INVALID; | |
764 | |
765 if (strchr(value, '=')) { | |
766 /* Form 1: Version arch=Version_string */ | |
767 v = strdup(value); | |
768 if (v == NULL) { | |
769 errlog(ERROR | FATAL, | |
770 "Internal Error: strdup() failure in " | |
771 "version_sanity()"); | |
772 } | |
773 | |
774 /* process each arch=version string */ | |
775 p = v; | |
776 while ((a = strtok(p, " \t\n"))) { | |
777 if ((retval = arch_version_sanity(a)) != VS_OK) { | |
778 *subv = strdup(a); | |
779 if (subv == NULL) { | |
780 errlog(ERROR | FATAL, | |
781 "Internal Error: strdup() failure " | |
782 "in version_sanity()"); | |
783 } | |
784 break; | |
785 } | |
786 if ((retval = set_version_arch(a)) != VS_OK) { | |
787 /* set the global Version_arch */ | |
788 *subv = strdup(a); | |
789 if (subv == NULL) { | |
790 errlog(ERROR | FATAL, | |
791 "Internal Error: strdup() failure " | |
792 "in version_sanity()"); | |
793 } | |
794 break; | |
795 } | |
796 p = NULL; | |
797 } | |
798 free(v); | |
799 } else { | |
800 /* Form 2: Version Version_string */ | |
801 if (valid_version(value)) { | |
802 retval = VS_OK; | |
803 } else { | |
804 *subv = strdup(value); | |
805 if (subv == NULL) { | |
806 errlog(ERROR | FATAL, | |
807 "Internal Error: strdup() failure " | |
808 "in version_sanity()"); | |
809 } | |
810 } | |
811 } | |
812 return (retval); | |
813 } | |
814 | |
815 /* | |
816 * arch_version_sanity() | |
817 * checks version lines of the form "arch=version" | |
818 * av MUST be a string of the form "arch=version" (no spaces) | |
819 * returns: VS_OK OK | |
820 * VS_INVARCH Invalid Architecture | |
821 * VS_INVVERS Invalid Version String | |
822 * VS_INVALID Both Versions are invalid; | |
823 */ | |
824 static int | |
825 arch_version_sanity(char *av) | |
826 { | |
827 char *p, *v; | |
828 int retval = VS_OK; | |
829 | |
830 p = strchr(av, '='); | |
831 if (p == NULL) { | |
832 errlog(INPUT|ERROR, "Error: Incorrect format of Version line"); | |
833 return (VS_INVALID); | |
834 } | |
835 | |
836 *p = '\0'; /* stick a '\0' where the '=' was */ | |
837 v = p + 1; | |
838 | |
839 if (valid_arch(av) == 0) | |
840 retval = VS_INVARCH; | |
841 | |
842 if (valid_version(v) == 0) | |
843 retval += VS_INVVERS; | |
844 | |
845 *p = '='; /* restore the '=' */ | |
846 | |
847 return (retval); | |
848 } | |
849 | |
850 /* | |
851 * writemapfile() | |
852 * called by xlator_endlib(); | |
853 * writes out the map file | |
854 */ | |
855 static void | |
856 writemapfile(FILE *mapfp) | |
857 { | |
858 bucket_t *l; /* List of buckets. */ | |
859 bucket_t *b; /* Bucket within list. */ | |
860 struct bucketlist *bl; | |
861 table_t *t; | |
862 int i = 0, n = 0; | |
863 char **p; | |
864 | |
865 errlog(BEGIN, "writemapfile() {"); | |
866 for (l = first_list(); l != NULL; l = next_list()) { | |
867 | |
868 for (b = first_from_list(l); b != NULL; b = next_from_list()) { | |
869 errlog(TRACING, "b_name = %s", b->b_name); | |
870 print_bucket(b); /* Debugging routine. */ | |
871 | |
872 if (!b->b_was_printed) { | |
873 /* Ok, we can print it. */ | |
874 b->b_was_printed = 1; | |
875 (void) fprintf(mapfp, "%s {\n", b->b_name); | |
876 | |
877 if (b->b_weak != 1) { | |
878 char *strtab; | |
879 | |
880 (void) fprintf(mapfp, " global:\n"); | |
881 | |
882 strtab = get_stringtable( | |
883 b->b_global_table, 0); | |
884 | |
885 if (strtab == NULL) { | |
886 /* | |
887 * There were no interfaces | |
888 * in the bucket. | |
889 * Insert a dummy entry | |
890 * to avoid a "weak version" | |
891 */ | |
892 (void) fprintf(mapfp, | |
893 "\t%s;\n", b->b_name); | |
894 } | |
895 } else { | |
896 (void) fprintf(mapfp, | |
897 " # Weak version\n"); | |
898 } | |
899 /* Print all the interfaces in the bucket. */ | |
900 t = b->b_global_table; | |
901 n = t->used; | |
902 | |
903 for (i = 0; i <= n; ++i) { | |
904 (void) fprintf(mapfp, "\t%s;\n", | |
905 get_stringtable(t, i)); | |
906 } | |
907 | |
908 if (b->b_has_protecteds) { | |
909 t = b->b_protected_table; | |
910 n = t->used; | |
911 | |
912 (void) fprintf(mapfp, | |
913 " protected:\n"); | |
914 | |
915 for (i = 0; i <= n; ++i) { | |
916 (void) fprintf(mapfp, "\t%s;\n", | |
917 get_stringtable(t, i)); | |
918 } | |
919 } | |
920 | |
921 /* Conditionally add ``local: *;''. */ | |
922 if (b->b_has_locals) { | |
923 (void) fprintf(mapfp, | |
924 " local:\n\t*;\n}"); | |
925 } else { | |
926 (void) fprintf(mapfp, "}"); | |
927 } | |
928 /* Print name of all parents. */ | |
929 for (p = parents_of(b); | |
930 p != NULL && *p != '\0'; ++p) { | |
931 (void) fprintf(mapfp, " %s", *p); | |
932 } | |
933 bl = b->b_uncles; | |
934 while (bl != NULL) { | |
935 (void) fprintf(mapfp, " %s", | |
936 bl->bl_bucket->b_name); | |
937 bl = bl->bl_next; | |
938 } | |
939 | |
940 (void) fprintf(mapfp, ";\n\n"); | |
941 } else { | |
942 /* | |
943 * We've printed this one before, | |
944 * so don't do it again. | |
945 */ | |
946 /*EMPTY*/; | |
947 } | |
948 } | |
949 } | |
950 errlog(END, "}"); | |
951 } | |
952 | |
953 /* | |
954 * set_version_arch () | |
955 * input must be a string of the form "arch=version" | |
956 * turns on bits of global Version_Arch that correspond to the "arch" | |
957 * return VS_OK upon success | |
958 * VS_INVARCH if architecture is invalid | |
959 * EINVAL on other failure | |
960 */ | |
961 static int | |
962 set_version_arch(const char *arch) | |
963 { | |
964 char *a, *p; | |
965 int x; | |
966 int retval = EINVAL; | |
967 | |
968 if (arch == NULL) | |
969 return (retval); | |
970 | |
971 a = strdup(arch); | |
972 if (a == NULL) { | |
973 errlog(ERROR | FATAL, | |
974 "Internal Error: strdup() failure in " | |
975 "set_version_arch()"); | |
976 } | |
977 | |
978 p = strchr(a, '='); | |
979 if (p) { | |
980 *p = '\0'; | |
981 x = arch_strtoi(a); | |
982 if (x == 0) { | |
983 errlog(INPUT|ERROR, | |
984 "Error: Invalid architecture: %s", a); | |
985 retval = VS_INVARCH; | |
986 } else { | |
987 Version_Arch |= x; | |
988 retval = 0; | |
989 } | |
990 } | |
991 | |
992 free(a); | |
993 return (retval); | |
994 } | |
995 | |
996 /* | |
997 * set_supported_arch () | |
998 * input must be a string listing the architectures to be supported | |
999 * turns on bits of global Supported_Arch that correspond to the architecture | |
1000 * return 0 upon success, EINVAL on failure | |
1001 */ | |
1002 static int | |
1003 set_supported_arch(const char *arch) | |
1004 { | |
1005 char *a, *p, *tmp; | |
1006 int retval = EINVAL; | |
1007 | |
1008 if (arch == NULL || *arch == '\0') | |
1009 return (EINVAL); | |
1010 | |
1011 tmp = strdup(arch); | |
1012 if (tmp == NULL) { | |
1013 errlog(ERROR | FATAL, "Internal Error: strdup() failure in " | |
1014 "set_supported_arch()"); | |
1015 } | |
1016 | |
1017 p = tmp; | |
1018 while ((a = strtok(p, " ,\t\n"))) { | |
1019 int x; | |
1020 x = arch_strtoi(a); | |
1021 if (x == 0) { | |
1022 errlog(INPUT|ERROR, | |
1023 "Error: Invalid architecture: %s", a); | |
1024 free(tmp); | |
1025 return (EINVAL); | |
1026 } | |
1027 Supported_Arch |= x; | |
1028 retval = 0; | |
1029 p = NULL; | |
1030 } | |
1031 | |
1032 free(tmp); | |
1033 return (retval); | |
1034 } |