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