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 * 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 } 1035