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
27 #pragma ident "%Z%%M% %I% %E% SMI"
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 *
xlator_init(const Translator_info * t_info)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
xlator_startlib(char const * libname)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
xlator_startfile(char const * filename)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
xlator_start_if(const Meta_info meta_info,const int token,char * value)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
xlator_take_kvpair(const Meta_info meta_info,const int token,char * value)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
xlator_end_if(const Meta_info M,const char * value)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
xlator_endfile(void)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
xlator_endlib(void)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
xlator_end(void)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 *
getversion(const char * value)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 *
getfilter(const char * value)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
version_sanity(const char * value,char ** subv)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
arch_version_sanity(char * av)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
writemapfile(FILE * mapfp)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
set_version_arch(const char * arch)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
set_supported_arch(const char * arch)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 }
1035