17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 55aefb655Srie * Common Development and Distribution License (the "License"). 65aefb655Srie * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 215aefb655Srie 227c478bd9Sstevel@tonic-gate /* 231007fd6fSAli Bahrami * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved. 247c478bd9Sstevel@tonic-gate */ 257257d1b4Sraf 267257d1b4Sraf /* 277257d1b4Sraf * Copyright (c) 1988 AT&T 287257d1b4Sraf * All Rights Reserved 297257d1b4Sraf */ 307257d1b4Sraf 317c478bd9Sstevel@tonic-gate /* 327c478bd9Sstevel@tonic-gate * Utility functions 337c478bd9Sstevel@tonic-gate */ 347c478bd9Sstevel@tonic-gate #include <unistd.h> 357c478bd9Sstevel@tonic-gate #include <stdio.h> 365aefb655Srie #include <stdarg.h> 377c478bd9Sstevel@tonic-gate #include <string.h> 387c478bd9Sstevel@tonic-gate #include <fcntl.h> 397c478bd9Sstevel@tonic-gate #include <sys/types.h> 407c478bd9Sstevel@tonic-gate #include <sys/mman.h> 417c478bd9Sstevel@tonic-gate #include <errno.h> 425aefb655Srie #include <sgs.h> 437257d1b4Sraf #include <libintl.h> 447c478bd9Sstevel@tonic-gate #include <debug.h> 457c478bd9Sstevel@tonic-gate #include "msg.h" 467c478bd9Sstevel@tonic-gate #include "_libld.h" 477c478bd9Sstevel@tonic-gate 487c478bd9Sstevel@tonic-gate /* 497c478bd9Sstevel@tonic-gate * libld_malloc() and dz_map() are used for both performance and for ease of 507c478bd9Sstevel@tonic-gate * programming: 517c478bd9Sstevel@tonic-gate * 527c478bd9Sstevel@tonic-gate * Performance: 537c478bd9Sstevel@tonic-gate * The link-edit is a short lived process which doesn't really free much 547c478bd9Sstevel@tonic-gate * of the dynamic memory that it requests. Because of this, it is more 557c478bd9Sstevel@tonic-gate * important to optimize for quick memory allocations than the 567c478bd9Sstevel@tonic-gate * re-usability of the memory. 577c478bd9Sstevel@tonic-gate * 587c478bd9Sstevel@tonic-gate * By also mmaping blocks of pages in from /dev/zero we don't need to 597c478bd9Sstevel@tonic-gate * waste the overhead of zeroing out these pages for calloc() requests. 607c478bd9Sstevel@tonic-gate * 617c478bd9Sstevel@tonic-gate * Memory Management: 627c478bd9Sstevel@tonic-gate * By doing all libld memory management through the ld_malloc routine 637c478bd9Sstevel@tonic-gate * it's much easier to free up all memory at the end by simply unmaping 647c478bd9Sstevel@tonic-gate * all of the blocks that were mapped in through dz_map(). This is much 657c478bd9Sstevel@tonic-gate * simpler then trying to track all of the libld structures that were 667c478bd9Sstevel@tonic-gate * dynamically allocate and are actually pointers into the ELF files. 677c478bd9Sstevel@tonic-gate * 687c478bd9Sstevel@tonic-gate * It's important that we can free up all of our dynamic memory because 697c478bd9Sstevel@tonic-gate * libld is used by ld.so.1 when it performs dlopen()'s of relocatable 707c478bd9Sstevel@tonic-gate * objects. 717c478bd9Sstevel@tonic-gate * 727c478bd9Sstevel@tonic-gate * Format: 737c478bd9Sstevel@tonic-gate * The memory blocks for each allocation store the size of the allocation 747c478bd9Sstevel@tonic-gate * in the first 8 bytes of the block. The pointer that is returned by 757c478bd9Sstevel@tonic-gate * libld_malloc() is actually the address of (block + 8): 767c478bd9Sstevel@tonic-gate * 777c478bd9Sstevel@tonic-gate * (addr - 8) block_size 787c478bd9Sstevel@tonic-gate * (addr) <allocated block> 797c478bd9Sstevel@tonic-gate * 807c478bd9Sstevel@tonic-gate * The size is retained in order to implement realloc(), and to perform 817c478bd9Sstevel@tonic-gate * the required memcpy(). 8 bytes are uses, as the memory area returned 827c478bd9Sstevel@tonic-gate * by libld_malloc() must be 8 byte-aligned. Even in a 32-bit environment, 837c478bd9Sstevel@tonic-gate * u_longlog_t pointers are employed. 847c478bd9Sstevel@tonic-gate * 850e233487SRod Evans * Map anonymous memory via MAP_ANON (added in Solaris 8). 867c478bd9Sstevel@tonic-gate */ 877c478bd9Sstevel@tonic-gate static void * 887c478bd9Sstevel@tonic-gate dz_map(size_t size) 897c478bd9Sstevel@tonic-gate { 907c478bd9Sstevel@tonic-gate void *addr; 917c478bd9Sstevel@tonic-gate 927c478bd9Sstevel@tonic-gate if ((addr = mmap(0, size, (PROT_READ | PROT_WRITE | PROT_EXEC), 930e233487SRod Evans (MAP_PRIVATE | MAP_ANON), -1, 0)) == MAP_FAILED) { 940e233487SRod Evans int err = errno; 951007fd6fSAli Bahrami eprintf(NULL, ERR_FATAL, MSG_INTL(MSG_SYS_MMAPANON), 960e233487SRod Evans strerror(err)); 977c478bd9Sstevel@tonic-gate return (MAP_FAILED); 987c478bd9Sstevel@tonic-gate } 997c478bd9Sstevel@tonic-gate return (addr); 1007c478bd9Sstevel@tonic-gate } 1017c478bd9Sstevel@tonic-gate 1027c478bd9Sstevel@tonic-gate void * 1037c478bd9Sstevel@tonic-gate libld_malloc(size_t size) 1047c478bd9Sstevel@tonic-gate { 1057c478bd9Sstevel@tonic-gate Ld_heap *chp = ld_heap; 1067c478bd9Sstevel@tonic-gate void *vptr; 1077c478bd9Sstevel@tonic-gate size_t asize = size + HEAPALIGN; 1087c478bd9Sstevel@tonic-gate 1097c478bd9Sstevel@tonic-gate /* 1107c478bd9Sstevel@tonic-gate * If this is the first allocation, or the allocation request is greater 1117c478bd9Sstevel@tonic-gate * than the current free space available, allocate a new heap. 1127c478bd9Sstevel@tonic-gate */ 11357ef7aa9SRod Evans if ((chp == NULL) || 1147c478bd9Sstevel@tonic-gate (((size_t)chp->lh_end - (size_t)chp->lh_free) <= asize)) { 1157c478bd9Sstevel@tonic-gate Ld_heap *nhp; 1167c478bd9Sstevel@tonic-gate size_t hsize = (size_t)S_ROUND(sizeof (Ld_heap), HEAPALIGN); 1177c478bd9Sstevel@tonic-gate size_t tsize = (size_t)S_ROUND((asize + hsize), HEAPALIGN); 1187c478bd9Sstevel@tonic-gate 1197c478bd9Sstevel@tonic-gate /* 1207c478bd9Sstevel@tonic-gate * Allocate a block that is at minimum 'HEAPBLOCK' size 1217c478bd9Sstevel@tonic-gate */ 1227c478bd9Sstevel@tonic-gate if (tsize < HEAPBLOCK) 1237c478bd9Sstevel@tonic-gate tsize = HEAPBLOCK; 1247c478bd9Sstevel@tonic-gate 1257c478bd9Sstevel@tonic-gate if ((nhp = dz_map(tsize)) == MAP_FAILED) 1260e233487SRod Evans return (NULL); 1277c478bd9Sstevel@tonic-gate 1287c478bd9Sstevel@tonic-gate nhp->lh_next = chp; 1297c478bd9Sstevel@tonic-gate nhp->lh_free = (void *)((size_t)nhp + hsize); 1307c478bd9Sstevel@tonic-gate nhp->lh_end = (void *)((size_t)nhp + tsize); 1317c478bd9Sstevel@tonic-gate 1327c478bd9Sstevel@tonic-gate ld_heap = chp = nhp; 1337c478bd9Sstevel@tonic-gate } 1347c478bd9Sstevel@tonic-gate vptr = chp->lh_free; 1357c478bd9Sstevel@tonic-gate 1367c478bd9Sstevel@tonic-gate /* 1377c478bd9Sstevel@tonic-gate * Assign size to head of allocated block (used by realloc), and 1387c478bd9Sstevel@tonic-gate * memory arena as then next 8-byte aligned offset. 1397c478bd9Sstevel@tonic-gate */ 1407c478bd9Sstevel@tonic-gate *((size_t *)vptr) = size; 1417c478bd9Sstevel@tonic-gate vptr = (void *)((size_t)vptr + HEAPALIGN); 1427c478bd9Sstevel@tonic-gate 1437c478bd9Sstevel@tonic-gate /* 1447c478bd9Sstevel@tonic-gate * Increment free to point to next available block 1457c478bd9Sstevel@tonic-gate */ 1467c478bd9Sstevel@tonic-gate chp->lh_free = (void *)S_ROUND((size_t)chp->lh_free + asize, 1477c478bd9Sstevel@tonic-gate HEAPALIGN); 1487c478bd9Sstevel@tonic-gate 1497c478bd9Sstevel@tonic-gate return (vptr); 1507c478bd9Sstevel@tonic-gate } 1517c478bd9Sstevel@tonic-gate 1527c478bd9Sstevel@tonic-gate void * 1537c478bd9Sstevel@tonic-gate libld_realloc(void *ptr, size_t size) 1547c478bd9Sstevel@tonic-gate { 1557c478bd9Sstevel@tonic-gate size_t psize; 1567c478bd9Sstevel@tonic-gate void *vptr; 1577c478bd9Sstevel@tonic-gate 1587c478bd9Sstevel@tonic-gate if (ptr == NULL) 1597c478bd9Sstevel@tonic-gate return (libld_malloc(size)); 1607c478bd9Sstevel@tonic-gate 1617c478bd9Sstevel@tonic-gate /* 1627c478bd9Sstevel@tonic-gate * Size of the allocated blocks is stored *just* before the blocks 1637c478bd9Sstevel@tonic-gate * address. 1647c478bd9Sstevel@tonic-gate */ 1657c478bd9Sstevel@tonic-gate psize = *((size_t *)((size_t)ptr - HEAPALIGN)); 1667c478bd9Sstevel@tonic-gate 1677c478bd9Sstevel@tonic-gate /* 1687c478bd9Sstevel@tonic-gate * If the block actually fits then just return. 1697c478bd9Sstevel@tonic-gate */ 1707c478bd9Sstevel@tonic-gate if (size <= psize) 1717c478bd9Sstevel@tonic-gate return (ptr); 1727c478bd9Sstevel@tonic-gate 17357ef7aa9SRod Evans if ((vptr = libld_malloc(size)) != NULL) 1747c478bd9Sstevel@tonic-gate (void) memcpy(vptr, ptr, psize); 1757c478bd9Sstevel@tonic-gate 1767c478bd9Sstevel@tonic-gate return (vptr); 1777c478bd9Sstevel@tonic-gate } 1787c478bd9Sstevel@tonic-gate 1797c478bd9Sstevel@tonic-gate void 1807c478bd9Sstevel@tonic-gate /* ARGSUSED 0 */ 1817c478bd9Sstevel@tonic-gate libld_free(void *ptr) 1827c478bd9Sstevel@tonic-gate { 1837c478bd9Sstevel@tonic-gate } 1847c478bd9Sstevel@tonic-gate 1857c478bd9Sstevel@tonic-gate /* 1867c478bd9Sstevel@tonic-gate * Determine if a shared object definition structure already exists and if 1877c478bd9Sstevel@tonic-gate * not create one. These definitions provide for recording information 1887c478bd9Sstevel@tonic-gate * regarding shared objects that are still to be processed. Once processed 1897c478bd9Sstevel@tonic-gate * shared objects are maintained on the ofl_sos list. The information 1907c478bd9Sstevel@tonic-gate * recorded in this structure includes: 1917c478bd9Sstevel@tonic-gate * 1927c478bd9Sstevel@tonic-gate * o DT_USED requirements. In these cases definitions are added during 1937c478bd9Sstevel@tonic-gate * mapfile processing of `-' entries (see map_dash()). 1947c478bd9Sstevel@tonic-gate * 1957c478bd9Sstevel@tonic-gate * o implicit NEEDED entries. As shared objects are processed from the 1967c478bd9Sstevel@tonic-gate * command line so any of their dependencies are recorded in these 1977c478bd9Sstevel@tonic-gate * structures for later processing (see process_dynamic()). 1987c478bd9Sstevel@tonic-gate * 1997c478bd9Sstevel@tonic-gate * o version requirements. Any explicit shared objects that have version 2007c478bd9Sstevel@tonic-gate * dependencies on other objects have their version requirements recorded. 2017c478bd9Sstevel@tonic-gate * In these cases definitions are added during mapfile processing of `-' 2027c478bd9Sstevel@tonic-gate * entries (see map_dash()). Also, shared objects may have versioning 2037c478bd9Sstevel@tonic-gate * requirements on their NEEDED entries. These cases are added during 2047c478bd9Sstevel@tonic-gate * their version processing (see vers_need_process()). 2057c478bd9Sstevel@tonic-gate * 2067c478bd9Sstevel@tonic-gate * Note: Both process_dynamic() and vers_need_process() may generate the 2077c478bd9Sstevel@tonic-gate * initial version definition structure because you can't rely on what 2087c478bd9Sstevel@tonic-gate * section (.dynamic or .SUNW_version) may be processed first from any 2097c478bd9Sstevel@tonic-gate * input file. 2107c478bd9Sstevel@tonic-gate */ 2117c478bd9Sstevel@tonic-gate Sdf_desc * 21257ef7aa9SRod Evans sdf_find(const char *name, APlist *alp) 2137c478bd9Sstevel@tonic-gate { 21457ef7aa9SRod Evans Aliste idx; 2157c478bd9Sstevel@tonic-gate Sdf_desc *sdf; 2167c478bd9Sstevel@tonic-gate 21757ef7aa9SRod Evans for (APLIST_TRAVERSE(alp, idx, sdf)) 2187c478bd9Sstevel@tonic-gate if (strcmp(name, sdf->sdf_name) == 0) 2197c478bd9Sstevel@tonic-gate return (sdf); 2207c478bd9Sstevel@tonic-gate 2210e233487SRod Evans return (NULL); 2227c478bd9Sstevel@tonic-gate } 2237c478bd9Sstevel@tonic-gate 2247c478bd9Sstevel@tonic-gate Sdf_desc * 22557ef7aa9SRod Evans sdf_add(const char *name, APlist **alpp) 2267c478bd9Sstevel@tonic-gate { 2277c478bd9Sstevel@tonic-gate Sdf_desc *sdf; 2287c478bd9Sstevel@tonic-gate 22957ef7aa9SRod Evans if ((sdf = libld_calloc(sizeof (Sdf_desc), 1)) == NULL) 2307c478bd9Sstevel@tonic-gate return ((Sdf_desc *)S_ERROR); 2317c478bd9Sstevel@tonic-gate 2327c478bd9Sstevel@tonic-gate sdf->sdf_name = name; 2337c478bd9Sstevel@tonic-gate 23457ef7aa9SRod Evans if (aplist_append(alpp, sdf, AL_CNT_OFL_LIBS) == NULL) 2357c478bd9Sstevel@tonic-gate return ((Sdf_desc *)S_ERROR); 23657ef7aa9SRod Evans 2377c478bd9Sstevel@tonic-gate return (sdf); 2387c478bd9Sstevel@tonic-gate } 2397c478bd9Sstevel@tonic-gate 2407c478bd9Sstevel@tonic-gate /* 2417c478bd9Sstevel@tonic-gate * Add a string, separated by a colon, to an existing string. Typically used 2427c478bd9Sstevel@tonic-gate * to maintain filter, rpath and audit names, of which there is normally only 2437c478bd9Sstevel@tonic-gate * one string supplied anyway. 2447c478bd9Sstevel@tonic-gate */ 2457c478bd9Sstevel@tonic-gate char * 2467c478bd9Sstevel@tonic-gate add_string(char *old, char *str) 2477c478bd9Sstevel@tonic-gate { 2487c478bd9Sstevel@tonic-gate char *new; 2497c478bd9Sstevel@tonic-gate 2507c478bd9Sstevel@tonic-gate if (old) { 2517c478bd9Sstevel@tonic-gate char *_str; 2527c478bd9Sstevel@tonic-gate size_t len; 2537c478bd9Sstevel@tonic-gate 2547c478bd9Sstevel@tonic-gate /* 2557c478bd9Sstevel@tonic-gate * If an original string exists, make sure this new string 2567c478bd9Sstevel@tonic-gate * doesn't get duplicated. 2577c478bd9Sstevel@tonic-gate */ 2587c478bd9Sstevel@tonic-gate if ((_str = strstr(old, str)) != NULL) { 2597c478bd9Sstevel@tonic-gate if (((_str == old) || 2607c478bd9Sstevel@tonic-gate (*(_str - 1) == *(MSG_ORIG(MSG_STR_COLON)))) && 2617c478bd9Sstevel@tonic-gate (_str += strlen(str)) && 2627c478bd9Sstevel@tonic-gate ((*_str == '\0') || 2637c478bd9Sstevel@tonic-gate (*_str == *(MSG_ORIG(MSG_STR_COLON))))) 2647c478bd9Sstevel@tonic-gate return (old); 2657c478bd9Sstevel@tonic-gate } 2667c478bd9Sstevel@tonic-gate 2677c478bd9Sstevel@tonic-gate len = strlen(old) + strlen(str) + 2; 2680e233487SRod Evans if ((new = libld_calloc(1, len)) == NULL) 2697c478bd9Sstevel@tonic-gate return ((char *)S_ERROR); 2707c478bd9Sstevel@tonic-gate (void) snprintf(new, len, MSG_ORIG(MSG_FMT_COLPATH), old, str); 2717c478bd9Sstevel@tonic-gate } else { 2720e233487SRod Evans if ((new = libld_malloc(strlen(str) + 1)) == NULL) 2737c478bd9Sstevel@tonic-gate return ((char *)S_ERROR); 2747c478bd9Sstevel@tonic-gate (void) strcpy(new, str); 2757c478bd9Sstevel@tonic-gate } 2767c478bd9Sstevel@tonic-gate 2777c478bd9Sstevel@tonic-gate return (new); 2787c478bd9Sstevel@tonic-gate } 2797c478bd9Sstevel@tonic-gate 2807c478bd9Sstevel@tonic-gate /* 281cdcc71c0SAli Bahrami * The GNU ld '-wrap=XXX' and '--wrap=XXX' options correspond to our 282cdcc71c0SAli Bahrami * '-z wrap=XXX'. When str2chr() does this conversion, we end up with 283cdcc71c0SAli Bahrami * the return character set to 'z' and optarg set to 'XXX'. This callback 284cdcc71c0SAli Bahrami * changes optarg to include the missing wrap= prefix. 285cdcc71c0SAli Bahrami * 286cdcc71c0SAli Bahrami * exit: 287cdcc71c0SAli Bahrami * Returns c on success, or '?' on error. 288cdcc71c0SAli Bahrami */ 289cdcc71c0SAli Bahrami static int 290cdcc71c0SAli Bahrami str2chr_wrap_cb(int c) 291cdcc71c0SAli Bahrami { 292cdcc71c0SAli Bahrami char *str; 293cdcc71c0SAli Bahrami size_t len = MSG_ARG_WRAP_SIZE + strlen(optarg) + 1; 294cdcc71c0SAli Bahrami 295cdcc71c0SAli Bahrami if ((str = libld_malloc(len)) == NULL) 296cdcc71c0SAli Bahrami return ('?'); 297cdcc71c0SAli Bahrami (void) snprintf(str, len, MSG_ORIG(MSG_FMT_STRCAT), 298cdcc71c0SAli Bahrami MSG_ORIG(MSG_ARG_WRAP), optarg); 299cdcc71c0SAli Bahrami optarg = str; 300cdcc71c0SAli Bahrami return (c); 301cdcc71c0SAli Bahrami } 302cdcc71c0SAli Bahrami 303cdcc71c0SAli Bahrami /* 304*c5accfb2SRichard Lowe * Determine whether this string, possibly with an associated option, should 305*c5accfb2SRichard Lowe * be translated to an option character. If so, update the optind and optarg 306*c5accfb2SRichard Lowe * and optopt as described for short options in getopt(3c). 307cdcc71c0SAli Bahrami * 308cdcc71c0SAli Bahrami * entry: 309cdcc71c0SAli Bahrami * lml - Link map list for debug messages 310cdcc71c0SAli Bahrami * ndx - Starting optind for current item 311cdcc71c0SAli Bahrami * argc, argv - Command line arguments 312cdcc71c0SAli Bahrami * arg - Option to be examined 313cdcc71c0SAli Bahrami * c, opt - Option character (c) and corresponding long name (opt) 314cdcc71c0SAli Bahrami * optsz - 0 if option does not accept a value. If option does 315cdcc71c0SAli Bahrami * accept a value, strlen(opt), giving the offset to the 316cdcc71c0SAli Bahrami * value if the option and value are combined in one string. 317cdcc71c0SAli Bahrami * cbfunc - NULL, or pointer to function to call if a translation is 318cdcc71c0SAli Bahrami * successful. 31992a02081SRod Evans */ 32092a02081SRod Evans static int 32192a02081SRod Evans str2chr(Lm_list *lml, int ndx, int argc, char **argv, char *arg, int c, 322cdcc71c0SAli Bahrami const char *opt, size_t optsz, int cbfunc(int)) 32392a02081SRod Evans { 32492a02081SRod Evans if (optsz == 0) { 32592a02081SRod Evans /* 32692a02081SRod Evans * Compare a single option (ie. there's no associated option 32792a02081SRod Evans * argument). 32892a02081SRod Evans */ 32992a02081SRod Evans if (strcmp(arg, opt) == 0) { 33092a02081SRod Evans DBG_CALL(Dbg_args_str2chr(lml, ndx, opt, c)); 33192a02081SRod Evans optind += 1; 332*c5accfb2SRichard Lowe optopt = c; 33392a02081SRod Evans return (c); 33492a02081SRod Evans } 33544a646f1SRichard Lowe } else if ((strcmp(arg, opt) == 0) || 33644a646f1SRichard Lowe ((arg[optsz] == '=') && strncmp(arg, opt, optsz) == 0)) { 33792a02081SRod Evans /* 33892a02081SRod Evans * Otherwise, compare the option name, which may be 33992a02081SRod Evans * concatenated with the option argument. 34092a02081SRod Evans */ 34192a02081SRod Evans DBG_CALL(Dbg_args_str2chr(lml, ndx, opt, c)); 34292a02081SRod Evans 34392a02081SRod Evans if (arg[optsz] == '\0') { 34492a02081SRod Evans /* 34592a02081SRod Evans * Optarg is the next argument (white space separated). 34692a02081SRod Evans * Make sure an optarg is available, and if not return 34792a02081SRod Evans * a failure to prevent any fall-through to the generic 34892a02081SRod Evans * getopt() processing. 349*c5accfb2SRichard Lowe * 350*c5accfb2SRichard Lowe * Since we'll be completely failing this option we 351*c5accfb2SRichard Lowe * don't want to update optopt with the translation, 352*c5accfb2SRichard Lowe * but also need to set it to _something_. Setting it 353*c5accfb2SRichard Lowe * to the '-' of the argument causes us to behave 354*c5accfb2SRichard Lowe * correctly. 35592a02081SRod Evans */ 35692a02081SRod Evans if ((++optind + 1) > argc) { 357*c5accfb2SRichard Lowe optopt = arg[0]; 35892a02081SRod Evans return ('?'); 35992a02081SRod Evans } 36092a02081SRod Evans optarg = argv[optind]; 36192a02081SRod Evans optind++; 36292a02081SRod Evans } else { 36392a02081SRod Evans /* 36492a02081SRod Evans * GNU option/option argument pairs can be represented 36592a02081SRod Evans * with a "=" separator. If this is the case, remove 36692a02081SRod Evans * the separator. 36792a02081SRod Evans */ 36892a02081SRod Evans optarg = &arg[optsz]; 36992a02081SRod Evans optind++; 37092a02081SRod Evans if (*optarg == '=') { 371*c5accfb2SRichard Lowe if (*(++optarg) == '\0') { 372*c5accfb2SRichard Lowe optopt = arg[0]; 37392a02081SRod Evans return ('?'); 37492a02081SRod Evans } 37592a02081SRod Evans } 376*c5accfb2SRichard Lowe } 377cdcc71c0SAli Bahrami 378cdcc71c0SAli Bahrami if (cbfunc != NULL) 379cdcc71c0SAli Bahrami c = (*cbfunc)(c); 380*c5accfb2SRichard Lowe optopt = c; 38192a02081SRod Evans return (c); 38292a02081SRod Evans } 38392a02081SRod Evans return (0); 38492a02081SRod Evans } 38592a02081SRod Evans 38692a02081SRod Evans /* 38792a02081SRod Evans * Parse an individual option. The intent of this function is to determine if 38892a02081SRod Evans * any known, non-Solaris options have been passed to ld(1). This condition 38992a02081SRod Evans * can occur as a result of build configuration tools, because of users 39092a02081SRod Evans * familiarity with other systems, or simply the users preferences. If a known 39192a02081SRod Evans * non-Solaris option can be determined, translate that option into the Solaris 39292a02081SRod Evans * counterpart. 39392a02081SRod Evans * 39492a02081SRod Evans * This function will probably never be a complete solution, as new, non-Solaris 39592a02081SRod Evans * options are discovered, their translation will have to be added. Other 39692a02081SRod Evans * non-Solaris options are incompatible with the Solaris link-editor, and will 39792a02081SRod Evans * never be recognized. We support what we can. 39892a02081SRod Evans */ 39992a02081SRod Evans int 40092a02081SRod Evans ld_getopt(Lm_list *lml, int ndx, int argc, char **argv) 40192a02081SRod Evans { 40292a02081SRod Evans int c; 40392a02081SRod Evans 40492a02081SRod Evans if ((optind < argc) && argv[optind] && (argv[optind][0] == '-')) { 40592a02081SRod Evans char *arg = &argv[optind][1]; 40692a02081SRod Evans 40792a02081SRod Evans switch (*arg) { 40892a02081SRod Evans case 'r': 40992a02081SRod Evans /* Translate -rpath <optarg> to -R <optarg> */ 41092a02081SRod Evans if ((c = str2chr(lml, ndx, argc, argv, arg, 'R', 41192a02081SRod Evans MSG_ORIG(MSG_ARG_T_RPATH), 412cdcc71c0SAli Bahrami MSG_ARG_T_RPATH_SIZE, NULL)) != 0) { 41392a02081SRod Evans return (c); 41492a02081SRod Evans } 41592a02081SRod Evans break; 41692a02081SRod Evans case 's': 41792a02081SRod Evans /* Translate -shared to -G */ 41892a02081SRod Evans if ((c = str2chr(lml, ndx, argc, argv, arg, 'G', 419cdcc71c0SAli Bahrami MSG_ORIG(MSG_ARG_T_SHARED), 0, NULL)) != 0) { 42092a02081SRod Evans return (c); 42192a02081SRod Evans 42292a02081SRod Evans /* Translate -soname <optarg> to -h <optarg> */ 42392a02081SRod Evans } else if ((c = str2chr(lml, ndx, argc, argv, arg, 'h', 42492a02081SRod Evans MSG_ORIG(MSG_ARG_T_SONAME), 425cdcc71c0SAli Bahrami MSG_ARG_T_SONAME_SIZE, NULL)) != 0) { 426cdcc71c0SAli Bahrami return (c); 427cdcc71c0SAli Bahrami } 428cdcc71c0SAli Bahrami break; 429cdcc71c0SAli Bahrami case 'w': 430cdcc71c0SAli Bahrami /* Translate -wrap to -z wrap= */ 431cdcc71c0SAli Bahrami if ((c = str2chr(lml, ndx, argc, argv, arg, 'z', 432cdcc71c0SAli Bahrami MSG_ORIG(MSG_ARG_T_WRAP) + 1, 433cdcc71c0SAli Bahrami MSG_ARG_T_WRAP_SIZE - 1, str2chr_wrap_cb)) != 0) { 43492a02081SRod Evans return (c); 43592a02081SRod Evans } 43692a02081SRod Evans break; 437551cffe3SAli Bahrami case '(': 438551cffe3SAli Bahrami /* 439551cffe3SAli Bahrami * Translate -( to -z rescan-start 440551cffe3SAli Bahrami */ 441551cffe3SAli Bahrami if ((c = str2chr(lml, ndx, argc, argv, 442cdcc71c0SAli Bahrami arg, 'z', MSG_ORIG(MSG_ARG_T_OPAR), 0, NULL)) != 443cdcc71c0SAli Bahrami 0) { 444551cffe3SAli Bahrami optarg = (char *)MSG_ORIG(MSG_ARG_RESCAN_START); 445551cffe3SAli Bahrami return (c); 446551cffe3SAli Bahrami } 447551cffe3SAli Bahrami break; 448551cffe3SAli Bahrami case ')': 449551cffe3SAli Bahrami /* 450551cffe3SAli Bahrami * Translate -) to -z rescan-end 451551cffe3SAli Bahrami */ 452551cffe3SAli Bahrami if ((c = str2chr(lml, ndx, argc, argv, 453cdcc71c0SAli Bahrami arg, 'z', MSG_ORIG(MSG_ARG_T_CPAR), 0, NULL)) != 454cdcc71c0SAli Bahrami 0) { 455551cffe3SAli Bahrami optarg = (char *)MSG_ORIG(MSG_ARG_RESCAN_END); 456551cffe3SAli Bahrami return (c); 457551cffe3SAli Bahrami } 458551cffe3SAli Bahrami break; 45992a02081SRod Evans case '-': 46092a02081SRod Evans switch (*(arg + 1)) { 46192a02081SRod Evans case 'a': 46292a02081SRod Evans /* 46392a02081SRod Evans * Translate --allow-multiple-definition to 46492a02081SRod Evans * -zmuldefs 46592a02081SRod Evans */ 46692a02081SRod Evans if ((c = str2chr(lml, ndx, argc, argv, arg, 'z', 467cdcc71c0SAli Bahrami MSG_ORIG(MSG_ARG_T_MULDEFS), 0, NULL)) != 468cdcc71c0SAli Bahrami 0) { 46992a02081SRod Evans optarg = 47092a02081SRod Evans (char *)MSG_ORIG(MSG_ARG_MULDEFS); 47192a02081SRod Evans return (c); 47292a02081SRod Evans 47392a02081SRod Evans /* 47492a02081SRod Evans * Translate --auxiliary <optarg> to 47592a02081SRod Evans * -f <optarg> 47692a02081SRod Evans */ 47792a02081SRod Evans } else if ((c = str2chr(lml, argc, ndx, argv, 47892a02081SRod Evans arg, 'f', MSG_ORIG(MSG_ARG_T_AUXFLTR), 479cdcc71c0SAli Bahrami MSG_ARG_T_AUXFLTR_SIZE, NULL)) != 0) { 48092a02081SRod Evans return (c); 48192a02081SRod Evans } 48292a02081SRod Evans break; 48392a02081SRod Evans case 'd': 48492a02081SRod Evans /* 48592a02081SRod Evans * Translate --dynamic-linker <optarg> to 48692a02081SRod Evans * -I <optarg> 48792a02081SRod Evans */ 48892a02081SRod Evans if ((c = str2chr(lml, ndx, argc, argv, arg, 'I', 48992a02081SRod Evans MSG_ORIG(MSG_ARG_T_INTERP), 490cdcc71c0SAli Bahrami MSG_ARG_T_INTERP_SIZE, NULL)) != 0) { 49192a02081SRod Evans return (c); 49292a02081SRod Evans } 49392a02081SRod Evans break; 49492a02081SRod Evans case 'e': 49592a02081SRod Evans /* Translate --entry <optarg> to -e <optarg> */ 49692a02081SRod Evans if ((c = str2chr(lml, ndx, argc, argv, arg, 'e', 49792a02081SRod Evans MSG_ORIG(MSG_ARG_T_ENTRY), 498cdcc71c0SAli Bahrami MSG_ARG_T_ENTRY_SIZE, NULL)) != 0) { 49992a02081SRod Evans return (c); 50092a02081SRod Evans } 501551cffe3SAli Bahrami /* 502551cffe3SAli Bahrami * Translate --end-group to -z rescan-end 503551cffe3SAli Bahrami */ 504551cffe3SAli Bahrami if ((c = str2chr(lml, ndx, argc, argv, 505cdcc71c0SAli Bahrami arg, 'z', MSG_ORIG(MSG_ARG_T_ENDGROUP), 506cdcc71c0SAli Bahrami 0, NULL)) != 0) { 507551cffe3SAli Bahrami optarg = (char *) 508551cffe3SAli Bahrami MSG_ORIG(MSG_ARG_RESCAN_END); 509551cffe3SAli Bahrami return (c); 510551cffe3SAli Bahrami } 51192a02081SRod Evans break; 51292a02081SRod Evans case 'f': 5131007fd6fSAli Bahrami /* 5141007fd6fSAli Bahrami * Translate --fatal-warnings to 5151007fd6fSAli Bahrami * -z fatal-warnings. 5161007fd6fSAli Bahrami */ 5171007fd6fSAli Bahrami if ((c = str2chr(lml, ndx, argc, argv, arg, 'z', 5181007fd6fSAli Bahrami MSG_ORIG(MSG_ARG_T_FATWARN), 5191007fd6fSAli Bahrami 0, NULL)) != 0) { 5201007fd6fSAli Bahrami optarg = (char *) 5211007fd6fSAli Bahrami MSG_ORIG(MSG_ARG_FATWARN); 5221007fd6fSAli Bahrami return (c); 5231007fd6fSAli Bahrami } 52492a02081SRod Evans /* Translate --filter <optarg> to -F <optarg> */ 52592a02081SRod Evans if ((c = str2chr(lml, ndx, argc, argv, arg, 'F', 52692a02081SRod Evans MSG_ORIG(MSG_ARG_T_STDFLTR), 527cdcc71c0SAli Bahrami MSG_ARG_T_STDFLTR_SIZE, NULL)) != 0) { 52892a02081SRod Evans return (c); 52992a02081SRod Evans } 53092a02081SRod Evans break; 53192a02081SRod Evans case 'h': 53292a02081SRod Evans /* Translate --help to -zhelp */ 53392a02081SRod Evans if ((c = str2chr(lml, ndx, argc, argv, arg, 'z', 534cdcc71c0SAli Bahrami MSG_ORIG(MSG_ARG_T_HELP), 0, NULL)) != 535cdcc71c0SAli Bahrami 0) { 53692a02081SRod Evans optarg = (char *)MSG_ORIG(MSG_ARG_HELP); 53792a02081SRod Evans return (c); 53892a02081SRod Evans } 53992a02081SRod Evans break; 54092a02081SRod Evans case 'l': 54192a02081SRod Evans /* 54292a02081SRod Evans * Translate --library <optarg> to -l <optarg> 54392a02081SRod Evans */ 54492a02081SRod Evans if ((c = str2chr(lml, ndx, argc, argv, arg, 'l', 54592a02081SRod Evans MSG_ORIG(MSG_ARG_T_LIBRARY), 546cdcc71c0SAli Bahrami MSG_ARG_T_LIBRARY_SIZE, NULL)) != 0) { 54792a02081SRod Evans return (c); 54892a02081SRod Evans 54992a02081SRod Evans /* 55092a02081SRod Evans * Translate --library-path <optarg> to 55192a02081SRod Evans * -L <optarg> 55292a02081SRod Evans */ 55392a02081SRod Evans } else if ((c = str2chr(lml, ndx, argc, argv, 55492a02081SRod Evans arg, 'L', MSG_ORIG(MSG_ARG_T_LIBPATH), 555cdcc71c0SAli Bahrami MSG_ARG_T_LIBPATH_SIZE, NULL)) != 0) { 55692a02081SRod Evans return (c); 55792a02081SRod Evans } 55892a02081SRod Evans break; 55992a02081SRod Evans case 'n': 5601007fd6fSAli Bahrami /* 5611007fd6fSAli Bahrami * Translate --no-fatal-warnings to 5621007fd6fSAli Bahrami * -z nofatal-warnings. 5631007fd6fSAli Bahrami */ 5641007fd6fSAli Bahrami if ((c = str2chr(lml, ndx, argc, argv, arg, 'z', 5651007fd6fSAli Bahrami MSG_ORIG(MSG_ARG_T_NOFATWARN), 5661007fd6fSAli Bahrami 0, NULL)) != 0) { 5671007fd6fSAli Bahrami optarg = (char *) 5681007fd6fSAli Bahrami MSG_ORIG(MSG_ARG_NOFATWARN); 5691007fd6fSAli Bahrami return (c); 5701007fd6fSAli Bahrami } 5711007fd6fSAli Bahrami 57292a02081SRod Evans /* Translate --no-undefined to -zdefs */ 57392a02081SRod Evans if ((c = str2chr(lml, ndx, argc, argv, arg, 'z', 574cdcc71c0SAli Bahrami MSG_ORIG(MSG_ARG_T_NOUNDEF), 0, NULL)) != 575cdcc71c0SAli Bahrami 0) { 57692a02081SRod Evans optarg = (char *)MSG_ORIG(MSG_ARG_DEFS); 57792a02081SRod Evans return (c); 57892a02081SRod Evans 57992a02081SRod Evans /* 58092a02081SRod Evans * Translate --no-whole-archive to 58192a02081SRod Evans * -z defaultextract 58292a02081SRod Evans */ 58392a02081SRod Evans } else if ((c = str2chr(lml, ndx, argc, argv, 584cdcc71c0SAli Bahrami arg, 'z', MSG_ORIG(MSG_ARG_T_NOWHOLEARC), 585cdcc71c0SAli Bahrami 0, NULL)) != 0) { 58692a02081SRod Evans optarg = 58792a02081SRod Evans (char *)MSG_ORIG(MSG_ARG_DFLEXTRT); 58892a02081SRod Evans return (c); 58992a02081SRod Evans } 59092a02081SRod Evans break; 59192a02081SRod Evans case 'o': 59292a02081SRod Evans /* Translate --output <optarg> to -o <optarg> */ 59392a02081SRod Evans if ((c = str2chr(lml, ndx, argc, argv, arg, 'o', 59492a02081SRod Evans MSG_ORIG(MSG_ARG_T_OUTPUT), 595cdcc71c0SAli Bahrami MSG_ARG_T_OUTPUT_SIZE, NULL)) != 0) { 59692a02081SRod Evans return (c); 59792a02081SRod Evans } 59892a02081SRod Evans break; 59992a02081SRod Evans case 'r': 60092a02081SRod Evans /* Translate --relocatable to -r */ 60192a02081SRod Evans if ((c = str2chr(lml, ndx, argc, argv, arg, 'r', 602cdcc71c0SAli Bahrami MSG_ORIG(MSG_ARG_T_RELOCATABLE), 0, 603cdcc71c0SAli Bahrami NULL)) != 0) { 60492a02081SRod Evans return (c); 60592a02081SRod Evans } 60692a02081SRod Evans break; 60792a02081SRod Evans case 's': 60892a02081SRod Evans /* Translate --strip-all to -s */ 60992a02081SRod Evans if ((c = str2chr(lml, ndx, argc, argv, arg, 's', 610cdcc71c0SAli Bahrami MSG_ORIG(MSG_ARG_T_STRIP), 0, NULL)) != 611cdcc71c0SAli Bahrami 0) { 61292a02081SRod Evans return (c); 61392a02081SRod Evans } 614551cffe3SAli Bahrami /* 615551cffe3SAli Bahrami * Translate --start-group to -z rescan-start 616551cffe3SAli Bahrami */ 617551cffe3SAli Bahrami if ((c = str2chr(lml, ndx, argc, argv, 618cdcc71c0SAli Bahrami arg, 'z', MSG_ORIG(MSG_ARG_T_STARTGROUP), 619cdcc71c0SAli Bahrami 0, NULL)) != 0) { 620551cffe3SAli Bahrami optarg = (char *) 621551cffe3SAli Bahrami MSG_ORIG(MSG_ARG_RESCAN_START); 622551cffe3SAli Bahrami return (c); 623551cffe3SAli Bahrami } 62492a02081SRod Evans break; 62592a02081SRod Evans case 'u': 62692a02081SRod Evans /* 62792a02081SRod Evans * Translate --undefined <optarg> to 62892a02081SRod Evans * -u <optarg> 62992a02081SRod Evans */ 63092a02081SRod Evans if ((c = str2chr(lml, ndx, argc, argv, arg, 'u', 63192a02081SRod Evans MSG_ORIG(MSG_ARG_T_UNDEF), 632cdcc71c0SAli Bahrami MSG_ARG_T_UNDEF_SIZE, NULL)) != 0) { 63392a02081SRod Evans return (c); 63492a02081SRod Evans } 63592a02081SRod Evans break; 63692a02081SRod Evans case 'v': 63792a02081SRod Evans /* Translate --version to -V */ 63892a02081SRod Evans if ((c = str2chr(lml, ndx, argc, argv, arg, 'V', 639cdcc71c0SAli Bahrami MSG_ORIG(MSG_ARG_T_VERSION), 0, NULL)) != 640cdcc71c0SAli Bahrami 0) { 64192a02081SRod Evans return (c); 64292a02081SRod Evans } 64392a02081SRod Evans break; 64492a02081SRod Evans case 'w': 64592a02081SRod Evans /* 64692a02081SRod Evans * Translate --whole-archive to -z alltextract 64792a02081SRod Evans */ 64892a02081SRod Evans if ((c = str2chr(lml, ndx, argc, argv, 649cdcc71c0SAli Bahrami arg, 'z', MSG_ORIG(MSG_ARG_T_WHOLEARC), 650cdcc71c0SAli Bahrami 0, NULL)) != 0) { 65192a02081SRod Evans optarg = 65292a02081SRod Evans (char *)MSG_ORIG(MSG_ARG_ALLEXTRT); 65392a02081SRod Evans return (c); 65492a02081SRod Evans } 655cdcc71c0SAli Bahrami /* 656cdcc71c0SAli Bahrami * Translate --wrap to -z wrap= 657cdcc71c0SAli Bahrami */ 658cdcc71c0SAli Bahrami if ((c = str2chr(lml, ndx, argc, argv, 659cdcc71c0SAli Bahrami arg, 'z', MSG_ORIG(MSG_ARG_T_WRAP), 660cdcc71c0SAli Bahrami MSG_ARG_T_WRAP_SIZE, str2chr_wrap_cb)) != 661cdcc71c0SAli Bahrami 0) { 662cdcc71c0SAli Bahrami return (c); 663cdcc71c0SAli Bahrami } 66492a02081SRod Evans break; 66592a02081SRod Evans } 66692a02081SRod Evans break; 66792a02081SRod Evans } 66892a02081SRod Evans } 669cdcc71c0SAli Bahrami 67092a02081SRod Evans if ((c = getopt(argc, argv, MSG_ORIG(MSG_STR_OPTIONS))) != -1) { 67192a02081SRod Evans /* 67292a02081SRod Evans * It is possible that a "-Wl," argument has been used to 67392a02081SRod Evans * specify an option. This isn't advertized ld(1) syntax, but 67492a02081SRod Evans * compiler drivers and configuration tools, have been known to 67592a02081SRod Evans * pass this compiler option to ld(1). Strip off the "-Wl," 67692a02081SRod Evans * prefix and pass the option through. 67792a02081SRod Evans */ 67892a02081SRod Evans if ((c == 'W') && (strncmp(optarg, 67992a02081SRod Evans MSG_ORIG(MSG_ARG_T_WL), MSG_ARG_T_WL_SIZE) == 0)) { 68092a02081SRod Evans DBG_CALL(Dbg_args_Wldel(lml, ndx, optarg)); 68192a02081SRod Evans c = optarg[MSG_ARG_T_WL_SIZE]; 68292a02081SRod Evans optarg += MSG_ARG_T_WL_SIZE + 1; 68392a02081SRod Evans } 68492a02081SRod Evans } 68592a02081SRod Evans 68692a02081SRod Evans return (c); 68792a02081SRod Evans } 68892a02081SRod Evans 68992a02081SRod Evans /* 690e64d0ff9SAli Bahrami * A compare routine for Isd_node AVL trees. 6916b3ba5bdSAli Bahrami */ 6926b3ba5bdSAli Bahrami int 6936b3ba5bdSAli Bahrami isdavl_compare(const void *n1, const void *n2) 6946b3ba5bdSAli Bahrami { 6956b3ba5bdSAli Bahrami uint_t hash1, hash2; 6966b3ba5bdSAli Bahrami const char *st1, *st2; 6976b3ba5bdSAli Bahrami int rc; 6986b3ba5bdSAli Bahrami 6996b3ba5bdSAli Bahrami hash1 = ((Isd_node *)n1)->isd_hash; 7006b3ba5bdSAli Bahrami hash2 = ((Isd_node *)n2)->isd_hash; 7016b3ba5bdSAli Bahrami 7026b3ba5bdSAli Bahrami if (hash1 > hash2) 7036b3ba5bdSAli Bahrami return (1); 7046b3ba5bdSAli Bahrami if (hash1 < hash2) 7056b3ba5bdSAli Bahrami return (-1); 7066b3ba5bdSAli Bahrami 707e64d0ff9SAli Bahrami st1 = ((Isd_node *)n1)->isd_name; 708e64d0ff9SAli Bahrami st2 = ((Isd_node *)n2)->isd_name; 7096b3ba5bdSAli Bahrami 7106b3ba5bdSAli Bahrami rc = strcmp(st1, st2); 7116b3ba5bdSAli Bahrami if (rc > 0) 7126b3ba5bdSAli Bahrami return (1); 7136b3ba5bdSAli Bahrami if (rc < 0) 7146b3ba5bdSAli Bahrami return (-1); 7156b3ba5bdSAli Bahrami return (0); 7166b3ba5bdSAli Bahrami } 7176b3ba5bdSAli Bahrami 7186b3ba5bdSAli Bahrami /* 7197257d1b4Sraf * Messaging support - funnel everything through dgettext(). 7207c478bd9Sstevel@tonic-gate */ 7217c478bd9Sstevel@tonic-gate const char * 7227c478bd9Sstevel@tonic-gate _libld_msg(Msg mid) 7237c478bd9Sstevel@tonic-gate { 7247257d1b4Sraf return (dgettext(MSG_ORIG(MSG_SUNW_OST_SGS), MSG_ORIG(mid))); 7257c478bd9Sstevel@tonic-gate } 7267c478bd9Sstevel@tonic-gate 7277c478bd9Sstevel@tonic-gate /* 7287c478bd9Sstevel@tonic-gate * Determine whether a symbol name should be demangled. 7297c478bd9Sstevel@tonic-gate */ 7307c478bd9Sstevel@tonic-gate const char * 7317c478bd9Sstevel@tonic-gate demangle(const char *name) 7327c478bd9Sstevel@tonic-gate { 7335aefb655Srie if (demangle_flag) 7345aefb655Srie return (Elf_demangle_name(name)); 7357c478bd9Sstevel@tonic-gate else 7367c478bd9Sstevel@tonic-gate return (name); 7377c478bd9Sstevel@tonic-gate } 73808278a5eSRod Evans 73908278a5eSRod Evans /* 74008278a5eSRod Evans * Compare a series of platform or machine hardware names. 74108278a5eSRod Evans */ 74208278a5eSRod Evans int 74308278a5eSRod Evans cap_names_match(Alist *alp1, Alist *alp2) 74408278a5eSRod Evans { 74508278a5eSRod Evans Capstr *capstr1; 74608278a5eSRod Evans Aliste idx1; 74708278a5eSRod Evans int match = 0; 74808278a5eSRod Evans Word nitems; 74908278a5eSRod Evans 75008278a5eSRod Evans if ((nitems = alist_nitems(alp1)) != alist_nitems(alp2)) 75108278a5eSRod Evans return (1); 75208278a5eSRod Evans 75308278a5eSRod Evans for (ALIST_TRAVERSE(alp1, idx1, capstr1)) { 75408278a5eSRod Evans Capstr *capstr2; 75508278a5eSRod Evans Aliste idx2; 75608278a5eSRod Evans 75708278a5eSRod Evans for (ALIST_TRAVERSE(alp2, idx2, capstr2)) { 75808278a5eSRod Evans if (strcmp(capstr1->cs_str, capstr2->cs_str)) 75908278a5eSRod Evans continue; 76008278a5eSRod Evans 76108278a5eSRod Evans match++; 76208278a5eSRod Evans break; 76308278a5eSRod Evans } 76408278a5eSRod Evans } 76508278a5eSRod Evans 76608278a5eSRod Evans if (nitems == match) 76708278a5eSRod Evans return (0); 76808278a5eSRod Evans 76908278a5eSRod Evans return (1); 77008278a5eSRod Evans } 771