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