1df57947fSPedro F. Giffuni /*- 2df57947fSPedro F. Giffuni * SPDX-License-Identifier: BSD-4-Clause 3df57947fSPedro F. Giffuni * 49c6f9240SPeter Wemm * Copyright (c) 2000, Boris Popov 59c6f9240SPeter Wemm * All rights reserved. 69c6f9240SPeter Wemm * 79c6f9240SPeter Wemm * Redistribution and use in source and binary forms, with or without 89c6f9240SPeter Wemm * modification, are permitted provided that the following conditions 99c6f9240SPeter Wemm * are met: 109c6f9240SPeter Wemm * 1. Redistributions of source code must retain the above copyright 119c6f9240SPeter Wemm * notice, this list of conditions and the following disclaimer. 129c6f9240SPeter Wemm * 2. Redistributions in binary form must reproduce the above copyright 139c6f9240SPeter Wemm * notice, this list of conditions and the following disclaimer in the 149c6f9240SPeter Wemm * documentation and/or other materials provided with the distribution. 159c6f9240SPeter Wemm * 3. All advertising materials mentioning features or use of this software 169c6f9240SPeter Wemm * must display the following acknowledgement: 179c6f9240SPeter Wemm * This product includes software developed by Boris Popov. 189c6f9240SPeter Wemm * 4. Neither the name of the author nor the names of any co-contributors 199c6f9240SPeter Wemm * may be used to endorse or promote products derived from this software 209c6f9240SPeter Wemm * without specific prior written permission. 219c6f9240SPeter Wemm * 229c6f9240SPeter Wemm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 239c6f9240SPeter Wemm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 249c6f9240SPeter Wemm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 259c6f9240SPeter Wemm * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 269c6f9240SPeter Wemm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 279c6f9240SPeter Wemm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 289c6f9240SPeter Wemm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 299c6f9240SPeter Wemm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 309c6f9240SPeter Wemm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 319c6f9240SPeter Wemm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 329c6f9240SPeter Wemm * SUCH DAMAGE. 339c6f9240SPeter Wemm */ 349c6f9240SPeter Wemm 35b7abc67eSMaxim Sobolev #include <sys/types.h> 369c6f9240SPeter Wemm #include <sys/param.h> 37493b2041SWarner Losh #include <sys/endian.h> 389c6f9240SPeter Wemm #include <sys/exec.h> 399c6f9240SPeter Wemm #include <sys/queue.h> 409c6f9240SPeter Wemm #include <sys/kernel.h> 419c6f9240SPeter Wemm #include <sys/reboot.h> 429c6f9240SPeter Wemm #include <sys/linker.h> 439c6f9240SPeter Wemm #include <sys/stat.h> 449c6f9240SPeter Wemm #include <sys/module.h> 45e2d0802cSEd Maste 46517a1827SWarner Losh #include <ctype.h> 479c6f9240SPeter Wemm #include <err.h> 48e2d0802cSEd Maste #include <errno.h> 499c6f9240SPeter Wemm #include <fts.h> 50e2d0802cSEd Maste #include <stdbool.h> 519c6f9240SPeter Wemm #include <stdio.h> 529c6f9240SPeter Wemm #include <stdlib.h> 53e2d0802cSEd Maste #include <string.h> 549c6f9240SPeter Wemm #include <unistd.h> 55e2d0802cSEd Maste #include <machine/elf.h> 569c6f9240SPeter Wemm 579c6f9240SPeter Wemm #include "ef.h" 589c6f9240SPeter Wemm 59493b2041SWarner Losh #define MAXRECSIZE (64 << 10) /* 64k */ 609c6f9240SPeter Wemm #define check(val) if ((error = (val)) != 0) break 619c6f9240SPeter Wemm 62e2d0802cSEd Maste static bool dflag; /* do not create a hint file, only write on stdout */ 639cb138bbSLuigi Rizzo static int verbose; 649c6f9240SPeter Wemm 659cb138bbSLuigi Rizzo static FILE *fxref; /* current hints file */ 669c6f9240SPeter Wemm 6787e5cd7cSMike Heffner static const char *xref_file = "linker.hints"; 689c6f9240SPeter Wemm 699cb138bbSLuigi Rizzo /* 709cb138bbSLuigi Rizzo * A record is stored in the static buffer recbuf before going to disk. 719cb138bbSLuigi Rizzo */ 729c6f9240SPeter Wemm static char recbuf[MAXRECSIZE]; 739cb138bbSLuigi Rizzo static int recpos; /* current write position */ 749cb138bbSLuigi Rizzo static int reccnt; /* total record written to this file so far */ 759c6f9240SPeter Wemm 769c6f9240SPeter Wemm static void 779c6f9240SPeter Wemm intalign(void) 789c6f9240SPeter Wemm { 79e2d0802cSEd Maste 80bf6911cdSMarcelo Araujo recpos = roundup2(recpos, sizeof(int)); 819c6f9240SPeter Wemm } 829c6f9240SPeter Wemm 839c6f9240SPeter Wemm static void 849c6f9240SPeter Wemm record_start(void) 859c6f9240SPeter Wemm { 86e2d0802cSEd Maste 879c6f9240SPeter Wemm recpos = 0; 889c6f9240SPeter Wemm memset(recbuf, 0, MAXRECSIZE); 899c6f9240SPeter Wemm } 909c6f9240SPeter Wemm 919c6f9240SPeter Wemm static int 929c6f9240SPeter Wemm record_end(void) 939c6f9240SPeter Wemm { 94e2d0802cSEd Maste 959cb138bbSLuigi Rizzo if (recpos == 0) 96e2d0802cSEd Maste return (0); 979c6f9240SPeter Wemm reccnt++; 989c6f9240SPeter Wemm intalign(); 999c6f9240SPeter Wemm fwrite(&recpos, sizeof(recpos), 1, fxref); 100e2d0802cSEd Maste return (fwrite(recbuf, recpos, 1, fxref) != 1 ? errno : 0); 1019c6f9240SPeter Wemm } 1029c6f9240SPeter Wemm 1039c6f9240SPeter Wemm static int 104e2d0802cSEd Maste record_buf(const void *buf, size_t size) 1059c6f9240SPeter Wemm { 106e2d0802cSEd Maste 1079c6f9240SPeter Wemm if (MAXRECSIZE - recpos < size) 1089c6f9240SPeter Wemm errx(1, "record buffer overflow"); 1099c6f9240SPeter Wemm memcpy(recbuf + recpos, buf, size); 1109c6f9240SPeter Wemm recpos += size; 111e2d0802cSEd Maste return (0); 1129c6f9240SPeter Wemm } 1139c6f9240SPeter Wemm 1149cb138bbSLuigi Rizzo /* 1159cb138bbSLuigi Rizzo * An int is stored in host order and aligned 1169cb138bbSLuigi Rizzo */ 1179c6f9240SPeter Wemm static int 1189c6f9240SPeter Wemm record_int(int val) 1199c6f9240SPeter Wemm { 120e2d0802cSEd Maste 1219c6f9240SPeter Wemm intalign(); 122e2d0802cSEd Maste return (record_buf(&val, sizeof(val))); 1239c6f9240SPeter Wemm } 1249c6f9240SPeter Wemm 1259cb138bbSLuigi Rizzo /* 1269cb138bbSLuigi Rizzo * A string is stored as 1-byte length plus data, no padding 1279cb138bbSLuigi Rizzo */ 1289c6f9240SPeter Wemm static int 1299c6f9240SPeter Wemm record_string(const char *str) 1309c6f9240SPeter Wemm { 131e2d0802cSEd Maste int error; 132e2d0802cSEd Maste size_t len; 1339cb138bbSLuigi Rizzo u_char val; 1349c6f9240SPeter Wemm 1359c6f9240SPeter Wemm if (dflag) 136e2d0802cSEd Maste return (0); 1379cb138bbSLuigi Rizzo val = len = strlen(str); 1389cb138bbSLuigi Rizzo if (len > 255) 1399cb138bbSLuigi Rizzo errx(1, "string %s too long", str); 1409cb138bbSLuigi Rizzo error = record_buf(&val, sizeof(val)); 141e2d0802cSEd Maste if (error != 0) 142e2d0802cSEd Maste return (error); 143e2d0802cSEd Maste return (record_buf(str, len)); 1449c6f9240SPeter Wemm } 1459c6f9240SPeter Wemm 146493b2041SWarner Losh /* From sys/isa/pnp.c */ 147493b2041SWarner Losh static char * 148493b2041SWarner Losh pnp_eisaformat(uint32_t id) 149493b2041SWarner Losh { 150493b2041SWarner Losh uint8_t *data; 151493b2041SWarner Losh static char idbuf[8]; 152493b2041SWarner Losh const char hextoascii[] = "0123456789abcdef"; 153493b2041SWarner Losh 154493b2041SWarner Losh id = htole32(id); 155493b2041SWarner Losh data = (uint8_t *)&id; 156493b2041SWarner Losh idbuf[0] = '@' + ((data[0] & 0x7c) >> 2); 157493b2041SWarner Losh idbuf[1] = '@' + (((data[0] & 0x3) << 3) + ((data[1] & 0xe0) >> 5)); 158493b2041SWarner Losh idbuf[2] = '@' + (data[1] & 0x1f); 159493b2041SWarner Losh idbuf[3] = hextoascii[(data[2] >> 4)]; 160493b2041SWarner Losh idbuf[4] = hextoascii[(data[2] & 0xf)]; 161493b2041SWarner Losh idbuf[5] = hextoascii[(data[3] >> 4)]; 162493b2041SWarner Losh idbuf[6] = hextoascii[(data[3] & 0xf)]; 163493b2041SWarner Losh idbuf[7] = 0; 164493b2041SWarner Losh return (idbuf); 165493b2041SWarner Losh } 166493b2041SWarner Losh 167493b2041SWarner Losh struct pnp_elt 168493b2041SWarner Losh { 169493b2041SWarner Losh int pe_kind; /* What kind of entry */ 170493b2041SWarner Losh #define TYPE_SZ_MASK 0x0f 171493b2041SWarner Losh #define TYPE_FLAGGED 0x10 /* all f's is a wildcard */ 172493b2041SWarner Losh #define TYPE_INT 0x20 /* Is a number */ 173493b2041SWarner Losh #define TYPE_PAIRED 0x40 174493b2041SWarner Losh #define TYPE_LE 0x80 /* Matches <= this value */ 175493b2041SWarner Losh #define TYPE_GE 0x100 /* Matches >= this value */ 176493b2041SWarner Losh #define TYPE_MASK 0x200 /* Specifies a mask to follow */ 177493b2041SWarner Losh #define TYPE_U8 (1 | TYPE_INT) 178493b2041SWarner Losh #define TYPE_V8 (1 | TYPE_INT | TYPE_FLAGGED) 179493b2041SWarner Losh #define TYPE_G16 (2 | TYPE_INT | TYPE_GE) 180493b2041SWarner Losh #define TYPE_L16 (2 | TYPE_INT | TYPE_LE) 181493b2041SWarner Losh #define TYPE_M16 (2 | TYPE_INT | TYPE_MASK) 182493b2041SWarner Losh #define TYPE_U16 (2 | TYPE_INT) 183493b2041SWarner Losh #define TYPE_V16 (2 | TYPE_INT | TYPE_FLAGGED) 184493b2041SWarner Losh #define TYPE_U32 (4 | TYPE_INT) 185493b2041SWarner Losh #define TYPE_V32 (4 | TYPE_INT | TYPE_FLAGGED) 186493b2041SWarner Losh #define TYPE_W32 (4 | TYPE_INT | TYPE_PAIRED) 187493b2041SWarner Losh #define TYPE_D 7 188493b2041SWarner Losh #define TYPE_Z 8 189493b2041SWarner Losh #define TYPE_P 9 190493b2041SWarner Losh #define TYPE_E 10 191493b2041SWarner Losh #define TYPE_T 11 192493b2041SWarner Losh int pe_offset; /* Offset within the element */ 193493b2041SWarner Losh char * pe_key; /* pnp key name */ 194493b2041SWarner Losh TAILQ_ENTRY(pnp_elt) next; /* Link */ 195493b2041SWarner Losh }; 196493b2041SWarner Losh typedef TAILQ_HEAD(pnp_head, pnp_elt) pnp_list; 197493b2041SWarner Losh 198493b2041SWarner Losh /* 199493b2041SWarner Losh * this function finds the data from the pnp table, as described by the 200493b2041SWarner Losh * the description and creates a new output (new_desc). This output table 201493b2041SWarner Losh * is a form that's easier for the agent that's automatically loading the 202493b2041SWarner Losh * modules. 203493b2041SWarner Losh * 204493b2041SWarner Losh * The format output is the simplified string from this routine in the 205493b2041SWarner Losh * same basic format as the pnp string, as documented in sys/module.h. 206493b2041SWarner Losh * First a string describing the format is output, the a count of the 207493b2041SWarner Losh * number of records, then each record. The format string also describes 208493b2041SWarner Losh * the length of each entry (though it isn't a fixed length when strings 209493b2041SWarner Losh * are present). 210493b2041SWarner Losh * 211493b2041SWarner Losh * type Output Meaning 212493b2041SWarner Losh * I uint32_t Integer equality comparison 213493b2041SWarner Losh * J uint32_t Pair of uint16_t fields converted to native 214a35ddacaSWarner Losh * byte order. The two fields both must match. 215493b2041SWarner Losh * G uint32_t Greater than or equal to 216493b2041SWarner Losh * L uint32_t Less than or equal to 217493b2041SWarner Losh * M uint32_t Mask of which fields to test. Fields that 218a35ddacaSWarner Losh * take up space increment the count. This 219a35ddacaSWarner Losh * field must be first, and resets the count. 220493b2041SWarner Losh * D string Description of the device this pnp info is for 221493b2041SWarner Losh * Z string pnp string must match this 222493b2041SWarner Losh * T nothing T fields set pnp values that must be true for 223493b2041SWarner Losh * the entire table. 224493b2041SWarner Losh * Values are packed the same way that other values are packed in this file. 225493b2041SWarner Losh * Strings and int32_t's start on a 32-bit boundary and are padded with 0 226493b2041SWarner Losh * bytes. Objects that are smaller than uint32_t are converted, without 227493b2041SWarner Losh * sign extension to uint32_t to simplify parsing downstream. 228493b2041SWarner Losh */ 229493b2041SWarner Losh static int 230493b2041SWarner Losh parse_pnp_list(const char *desc, char **new_desc, pnp_list *list) 231493b2041SWarner Losh { 232e2d0802cSEd Maste const char *walker, *ep; 233493b2041SWarner Losh const char *colon, *semi; 234493b2041SWarner Losh struct pnp_elt *elt; 235493b2041SWarner Losh char type[8], key[32]; 236493b2041SWarner Losh int off; 237a98fa52eSJessica Clarke size_t new_desc_size; 238a98fa52eSJessica Clarke FILE *fp; 239493b2041SWarner Losh 240*c40fa3dcSJohn Baldwin TAILQ_INIT(list); 241e2d0802cSEd Maste walker = desc; 242e2d0802cSEd Maste ep = desc + strlen(desc); 243493b2041SWarner Losh off = 0; 244a98fa52eSJessica Clarke fp = open_memstream(new_desc, &new_desc_size); 245a98fa52eSJessica Clarke if (fp == NULL) 246a98fa52eSJessica Clarke err(1, "Could not open new memory stream"); 247493b2041SWarner Losh if (verbose > 1) 248493b2041SWarner Losh printf("Converting %s into a list\n", desc); 249493b2041SWarner Losh while (walker < ep) { 250493b2041SWarner Losh colon = strchr(walker, ':'); 251493b2041SWarner Losh semi = strchr(walker, ';'); 252493b2041SWarner Losh if (semi != NULL && semi < colon) 253493b2041SWarner Losh goto err; 254493b2041SWarner Losh if (colon - walker > sizeof(type)) 255493b2041SWarner Losh goto err; 256493b2041SWarner Losh strncpy(type, walker, colon - walker); 257493b2041SWarner Losh type[colon - walker] = '\0'; 258e2d0802cSEd Maste if (semi != NULL) { 259493b2041SWarner Losh if (semi - colon >= sizeof(key)) 260493b2041SWarner Losh goto err; 261493b2041SWarner Losh strncpy(key, colon + 1, semi - colon - 1); 262493b2041SWarner Losh key[semi - colon - 1] = '\0'; 263493b2041SWarner Losh walker = semi + 1; 264517a1827SWarner Losh /* Fail safe if we have spaces after ; */ 265517a1827SWarner Losh while (walker < ep && isspace(*walker)) 266517a1827SWarner Losh walker++; 267493b2041SWarner Losh } else { 268493b2041SWarner Losh if (strlen(colon + 1) >= sizeof(key)) 269493b2041SWarner Losh goto err; 270493b2041SWarner Losh strcpy(key, colon + 1); 271493b2041SWarner Losh walker = ep; 272493b2041SWarner Losh } 273493b2041SWarner Losh if (verbose > 1) 274493b2041SWarner Losh printf("Found type %s for name %s\n", type, key); 275493b2041SWarner Losh /* Skip pointer place holders */ 276493b2041SWarner Losh if (strcmp(type, "P") == 0) { 277493b2041SWarner Losh off += sizeof(void *); 278493b2041SWarner Losh continue; 279493b2041SWarner Losh } 280493b2041SWarner Losh 281493b2041SWarner Losh /* 282493b2041SWarner Losh * Add a node of the appropriate type 283493b2041SWarner Losh */ 284493b2041SWarner Losh elt = malloc(sizeof(struct pnp_elt) + strlen(key) + 1); 285493b2041SWarner Losh TAILQ_INSERT_TAIL(list, elt, next); 286493b2041SWarner Losh elt->pe_key = (char *)(elt + 1); 287493b2041SWarner Losh elt->pe_offset = off; 288493b2041SWarner Losh if (strcmp(type, "U8") == 0) 289493b2041SWarner Losh elt->pe_kind = TYPE_U8; 290493b2041SWarner Losh else if (strcmp(type, "V8") == 0) 291493b2041SWarner Losh elt->pe_kind = TYPE_V8; 292493b2041SWarner Losh else if (strcmp(type, "G16") == 0) 293493b2041SWarner Losh elt->pe_kind = TYPE_G16; 294493b2041SWarner Losh else if (strcmp(type, "L16") == 0) 295493b2041SWarner Losh elt->pe_kind = TYPE_L16; 296493b2041SWarner Losh else if (strcmp(type, "M16") == 0) 297493b2041SWarner Losh elt->pe_kind = TYPE_M16; 298493b2041SWarner Losh else if (strcmp(type, "U16") == 0) 299493b2041SWarner Losh elt->pe_kind = TYPE_U16; 300493b2041SWarner Losh else if (strcmp(type, "V16") == 0) 301493b2041SWarner Losh elt->pe_kind = TYPE_V16; 302493b2041SWarner Losh else if (strcmp(type, "U32") == 0) 303493b2041SWarner Losh elt->pe_kind = TYPE_U32; 304493b2041SWarner Losh else if (strcmp(type, "V32") == 0) 305493b2041SWarner Losh elt->pe_kind = TYPE_V32; 306493b2041SWarner Losh else if (strcmp(type, "W32") == 0) 307493b2041SWarner Losh elt->pe_kind = TYPE_W32; 308493b2041SWarner Losh else if (strcmp(type, "D") == 0) /* description char * */ 309493b2041SWarner Losh elt->pe_kind = TYPE_D; 310493b2041SWarner Losh else if (strcmp(type, "Z") == 0) /* char * to match */ 311493b2041SWarner Losh elt->pe_kind = TYPE_Z; 312493b2041SWarner Losh else if (strcmp(type, "P") == 0) /* Pointer -- ignored */ 313493b2041SWarner Losh elt->pe_kind = TYPE_P; 314493b2041SWarner Losh else if (strcmp(type, "E") == 0) /* EISA PNP ID, as uint32_t */ 315493b2041SWarner Losh elt->pe_kind = TYPE_E; 316493b2041SWarner Losh else if (strcmp(type, "T") == 0) 317493b2041SWarner Losh elt->pe_kind = TYPE_T; 318493b2041SWarner Losh else 319493b2041SWarner Losh goto err; 320493b2041SWarner Losh /* 321493b2041SWarner Losh * Maybe the rounding here needs to be more nuanced and/or somehow 322493b2041SWarner Losh * architecture specific. Fortunately, most tables in the system 323493b2041SWarner Losh * have sane ordering of types. 324493b2041SWarner Losh */ 325493b2041SWarner Losh if (elt->pe_kind & TYPE_INT) { 326493b2041SWarner Losh elt->pe_offset = roundup2(elt->pe_offset, elt->pe_kind & TYPE_SZ_MASK); 327493b2041SWarner Losh off = elt->pe_offset + (elt->pe_kind & TYPE_SZ_MASK); 328493b2041SWarner Losh } else if (elt->pe_kind == TYPE_E) { 329493b2041SWarner Losh /* Type E stored as Int, displays as string */ 330493b2041SWarner Losh elt->pe_offset = roundup2(elt->pe_offset, sizeof(uint32_t)); 331493b2041SWarner Losh off = elt->pe_offset + sizeof(uint32_t); 332493b2041SWarner Losh } else if (elt->pe_kind == TYPE_T) { 333493b2041SWarner Losh /* doesn't actually consume space in the table */ 334493b2041SWarner Losh off = elt->pe_offset; 335493b2041SWarner Losh } else { 336493b2041SWarner Losh elt->pe_offset = roundup2(elt->pe_offset, sizeof(void *)); 337493b2041SWarner Losh off = elt->pe_offset + sizeof(void *); 338493b2041SWarner Losh } 339493b2041SWarner Losh if (elt->pe_kind & TYPE_PAIRED) { 340a98fa52eSJessica Clarke char *word, *ctx, newtype; 341493b2041SWarner Losh 342493b2041SWarner Losh for (word = strtok_r(key, "/", &ctx); 343493b2041SWarner Losh word; word = strtok_r(NULL, "/", &ctx)) { 344a98fa52eSJessica Clarke newtype = elt->pe_kind & TYPE_FLAGGED ? 'J' : 'I'; 345a98fa52eSJessica Clarke fprintf(fp, "%c:%s;", newtype, word); 346493b2041SWarner Losh } 347493b2041SWarner Losh } 348493b2041SWarner Losh else { 349a98fa52eSJessica Clarke char newtype; 350a98fa52eSJessica Clarke 351493b2041SWarner Losh if (elt->pe_kind & TYPE_FLAGGED) 352a98fa52eSJessica Clarke newtype = 'J'; 353493b2041SWarner Losh else if (elt->pe_kind & TYPE_GE) 354a98fa52eSJessica Clarke newtype = 'G'; 355493b2041SWarner Losh else if (elt->pe_kind & TYPE_LE) 356a98fa52eSJessica Clarke newtype = 'L'; 357493b2041SWarner Losh else if (elt->pe_kind & TYPE_MASK) 358a98fa52eSJessica Clarke newtype = 'M'; 359493b2041SWarner Losh else if (elt->pe_kind & TYPE_INT) 360a98fa52eSJessica Clarke newtype = 'I'; 361493b2041SWarner Losh else if (elt->pe_kind == TYPE_D) 362a98fa52eSJessica Clarke newtype = 'D'; 363493b2041SWarner Losh else if (elt->pe_kind == TYPE_Z || elt->pe_kind == TYPE_E) 364a98fa52eSJessica Clarke newtype = 'Z'; 365493b2041SWarner Losh else if (elt->pe_kind == TYPE_T) 366a98fa52eSJessica Clarke newtype = 'T'; 367493b2041SWarner Losh else 368493b2041SWarner Losh errx(1, "Impossible type %x\n", elt->pe_kind); 369a98fa52eSJessica Clarke fprintf(fp, "%c:%s;", newtype, key); 370493b2041SWarner Losh } 371493b2041SWarner Losh } 372a98fa52eSJessica Clarke if (ferror(fp) != 0) { 373a98fa52eSJessica Clarke fclose(fp); 374a98fa52eSJessica Clarke errx(1, "Exhausted space converting description %s", desc); 375a98fa52eSJessica Clarke } 376a98fa52eSJessica Clarke if (fclose(fp) != 0) 377a98fa52eSJessica Clarke errx(1, "Failed to close memory stream"); 378e2d0802cSEd Maste return (0); 379493b2041SWarner Losh err: 380493b2041SWarner Losh errx(1, "Parse error of description string %s", desc); 381493b2041SWarner Losh } 382493b2041SWarner Losh 383*c40fa3dcSJohn Baldwin static void 384*c40fa3dcSJohn Baldwin free_pnp_list(char *new_desc, pnp_list *list) 3859c6f9240SPeter Wemm { 386493b2041SWarner Losh struct pnp_elt *elt, *elt_tmp; 387493b2041SWarner Losh 388*c40fa3dcSJohn Baldwin TAILQ_FOREACH_SAFE(elt, list, next, elt_tmp) { 389*c40fa3dcSJohn Baldwin TAILQ_REMOVE(list, elt, next); 390*c40fa3dcSJohn Baldwin free(elt); 391*c40fa3dcSJohn Baldwin } 392*c40fa3dcSJohn Baldwin free(new_desc); 393*c40fa3dcSJohn Baldwin } 394493b2041SWarner Losh 395*c40fa3dcSJohn Baldwin static void 396*c40fa3dcSJohn Baldwin parse_pnp_entry(struct elf_file *ef, struct pnp_elt *elt, const char *walker) 397*c40fa3dcSJohn Baldwin { 398493b2041SWarner Losh uint8_t v1; 399493b2041SWarner Losh uint16_t v2; 400493b2041SWarner Losh uint32_t v4; 401493b2041SWarner Losh int value; 402493b2041SWarner Losh char buffer[1024]; 403493b2041SWarner Losh 404493b2041SWarner Losh if (elt->pe_kind == TYPE_W32) { 405493b2041SWarner Losh memcpy(&v4, walker + elt->pe_offset, sizeof(v4)); 406493b2041SWarner Losh value = v4 & 0xffff; 407493b2041SWarner Losh record_int(value); 408493b2041SWarner Losh if (verbose > 1) 409493b2041SWarner Losh printf("W32:%#x", value); 410493b2041SWarner Losh value = (v4 >> 16) & 0xffff; 411493b2041SWarner Losh record_int(value); 412493b2041SWarner Losh if (verbose > 1) 413493b2041SWarner Losh printf(":%#x;", value); 414493b2041SWarner Losh } else if (elt->pe_kind & TYPE_INT) { 415493b2041SWarner Losh switch (elt->pe_kind & TYPE_SZ_MASK) { 416493b2041SWarner Losh case 1: 417493b2041SWarner Losh memcpy(&v1, walker + elt->pe_offset, sizeof(v1)); 418493b2041SWarner Losh if ((elt->pe_kind & TYPE_FLAGGED) && v1 == 0xff) 419493b2041SWarner Losh value = -1; 420493b2041SWarner Losh else 421493b2041SWarner Losh value = v1; 422493b2041SWarner Losh break; 423493b2041SWarner Losh case 2: 424493b2041SWarner Losh memcpy(&v2, walker + elt->pe_offset, sizeof(v2)); 425493b2041SWarner Losh if ((elt->pe_kind & TYPE_FLAGGED) && v2 == 0xffff) 426493b2041SWarner Losh value = -1; 427493b2041SWarner Losh else 428493b2041SWarner Losh value = v2; 429493b2041SWarner Losh break; 430493b2041SWarner Losh case 4: 431493b2041SWarner Losh memcpy(&v4, walker + elt->pe_offset, sizeof(v4)); 432493b2041SWarner Losh if ((elt->pe_kind & TYPE_FLAGGED) && v4 == 0xffffffff) 433493b2041SWarner Losh value = -1; 434493b2041SWarner Losh else 435493b2041SWarner Losh value = v4; 436493b2041SWarner Losh break; 437493b2041SWarner Losh default: 438493b2041SWarner Losh errx(1, "Invalid size somehow %#x", elt->pe_kind); 439b03747e9SWarner Losh } 440493b2041SWarner Losh if (verbose > 1) 441493b2041SWarner Losh printf("I:%#x;", value); 442493b2041SWarner Losh record_int(value); 443493b2041SWarner Losh } else if (elt->pe_kind == TYPE_T) { 444493b2041SWarner Losh /* Do nothing */ 445493b2041SWarner Losh } else { /* E, Z or D -- P already filtered */ 446493b2041SWarner Losh if (elt->pe_kind == TYPE_E) { 447493b2041SWarner Losh memcpy(&v4, walker + elt->pe_offset, sizeof(v4)); 448493b2041SWarner Losh strcpy(buffer, pnp_eisaformat(v4)); 449493b2041SWarner Losh } else { 450493b2041SWarner Losh char *ptr; 451493b2041SWarner Losh 452493b2041SWarner Losh ptr = *(char **)(walker + elt->pe_offset); 453493b2041SWarner Losh buffer[0] = '\0'; 4541dcace5bSMarcelo Araujo if (ptr != NULL) { 455ee150a33SWarner Losh EF_SEG_READ_STRING(ef, (Elf_Off)ptr, 456493b2041SWarner Losh sizeof(buffer), buffer); 457493b2041SWarner Losh buffer[sizeof(buffer) - 1] = '\0'; 458493b2041SWarner Losh } 459493b2041SWarner Losh } 460493b2041SWarner Losh if (verbose > 1) 461*c40fa3dcSJohn Baldwin printf("%c:%s;", elt->pe_kind == TYPE_E ? 'E' : 462*c40fa3dcSJohn Baldwin (elt->pe_kind == TYPE_Z ? 'Z' : 'D'), buffer); 463493b2041SWarner Losh record_string(buffer); 464493b2041SWarner Losh } 465493b2041SWarner Losh } 466*c40fa3dcSJohn Baldwin 467*c40fa3dcSJohn Baldwin static void 468*c40fa3dcSJohn Baldwin record_pnp_info(struct elf_file *ef, const char *cval, 469*c40fa3dcSJohn Baldwin struct mod_pnp_match_info *pnp, const char *descr) 470*c40fa3dcSJohn Baldwin { 471*c40fa3dcSJohn Baldwin pnp_list list; 472*c40fa3dcSJohn Baldwin struct pnp_elt *elt; 473*c40fa3dcSJohn Baldwin char *new_descr, *walker; 474*c40fa3dcSJohn Baldwin void *table; 475*c40fa3dcSJohn Baldwin size_t len; 476*c40fa3dcSJohn Baldwin int error, i; 477*c40fa3dcSJohn Baldwin 478*c40fa3dcSJohn Baldwin if (verbose > 1) 479*c40fa3dcSJohn Baldwin printf(" pnp info for bus %s format %s %d entries of %d bytes\n", 480*c40fa3dcSJohn Baldwin cval, descr, pnp->num_entry, pnp->entry_len); 481*c40fa3dcSJohn Baldwin 482*c40fa3dcSJohn Baldwin /* 483*c40fa3dcSJohn Baldwin * Parse descr to weed out the chaff and to create a list 484*c40fa3dcSJohn Baldwin * of offsets to output. 485*c40fa3dcSJohn Baldwin */ 486*c40fa3dcSJohn Baldwin parse_pnp_list(descr, &new_descr, &list); 487*c40fa3dcSJohn Baldwin record_int(MDT_PNP_INFO); 488*c40fa3dcSJohn Baldwin record_string(cval); 489*c40fa3dcSJohn Baldwin record_string(new_descr); 490*c40fa3dcSJohn Baldwin record_int(pnp->num_entry); 491*c40fa3dcSJohn Baldwin len = pnp->num_entry * pnp->entry_len; 492*c40fa3dcSJohn Baldwin table = malloc(len); 493*c40fa3dcSJohn Baldwin error = EF_SEG_READ_REL(ef, (Elf_Off)pnp->table, len, table); 494*c40fa3dcSJohn Baldwin if (error != 0) { 495*c40fa3dcSJohn Baldwin free_pnp_list(new_descr, &list); 496*c40fa3dcSJohn Baldwin free(table); 497*c40fa3dcSJohn Baldwin return; 498*c40fa3dcSJohn Baldwin } 499*c40fa3dcSJohn Baldwin 500*c40fa3dcSJohn Baldwin /* 501*c40fa3dcSJohn Baldwin * Walk the list and output things. We've collapsed all the 502*c40fa3dcSJohn Baldwin * variant forms of the table down to just ints and strings. 503*c40fa3dcSJohn Baldwin */ 504*c40fa3dcSJohn Baldwin walker = table; 505*c40fa3dcSJohn Baldwin for (i = 0; i < pnp->num_entry; i++) { 506*c40fa3dcSJohn Baldwin TAILQ_FOREACH(elt, &list, next) { 507*c40fa3dcSJohn Baldwin parse_pnp_entry(ef, elt, walker); 508*c40fa3dcSJohn Baldwin } 509493b2041SWarner Losh if (verbose > 1) 510493b2041SWarner Losh printf("\n"); 511*c40fa3dcSJohn Baldwin walker += pnp->entry_len; 512493b2041SWarner Losh } 513*c40fa3dcSJohn Baldwin 514493b2041SWarner Losh /* Now free it */ 515*c40fa3dcSJohn Baldwin free_pnp_list(new_descr, &list); 516493b2041SWarner Losh free(table); 517493b2041SWarner Losh } 518*c40fa3dcSJohn Baldwin 519*c40fa3dcSJohn Baldwin static int 520*c40fa3dcSJohn Baldwin parse_entry(struct mod_metadata *md, const char *cval, 521*c40fa3dcSJohn Baldwin struct elf_file *ef, const char *kldname) 522*c40fa3dcSJohn Baldwin { 523*c40fa3dcSJohn Baldwin struct mod_depend mdp; 524*c40fa3dcSJohn Baldwin struct mod_version mdv; 525*c40fa3dcSJohn Baldwin struct mod_pnp_match_info pnp; 526*c40fa3dcSJohn Baldwin char descr[1024]; 527*c40fa3dcSJohn Baldwin Elf_Off data; 528*c40fa3dcSJohn Baldwin int error; 529*c40fa3dcSJohn Baldwin 530*c40fa3dcSJohn Baldwin data = (Elf_Off)md->md_data; 531*c40fa3dcSJohn Baldwin error = 0; 532*c40fa3dcSJohn Baldwin record_start(); 533*c40fa3dcSJohn Baldwin switch (md->md_type) { 534*c40fa3dcSJohn Baldwin case MDT_DEPEND: 535*c40fa3dcSJohn Baldwin if (!dflag) 536*c40fa3dcSJohn Baldwin break; 537*c40fa3dcSJohn Baldwin check(EF_SEG_READ(ef, data, sizeof(mdp), &mdp)); 538*c40fa3dcSJohn Baldwin printf(" depends on %s.%d (%d,%d)\n", cval, 539*c40fa3dcSJohn Baldwin mdp.md_ver_preferred, mdp.md_ver_minimum, mdp.md_ver_maximum); 540*c40fa3dcSJohn Baldwin break; 541*c40fa3dcSJohn Baldwin case MDT_VERSION: 542*c40fa3dcSJohn Baldwin check(EF_SEG_READ(ef, data, sizeof(mdv), &mdv)); 543*c40fa3dcSJohn Baldwin if (dflag) { 544*c40fa3dcSJohn Baldwin printf(" interface %s.%d\n", cval, mdv.mv_version); 545*c40fa3dcSJohn Baldwin } else { 546*c40fa3dcSJohn Baldwin record_int(MDT_VERSION); 547*c40fa3dcSJohn Baldwin record_string(cval); 548*c40fa3dcSJohn Baldwin record_int(mdv.mv_version); 549*c40fa3dcSJohn Baldwin record_string(kldname); 550*c40fa3dcSJohn Baldwin } 551*c40fa3dcSJohn Baldwin break; 552*c40fa3dcSJohn Baldwin case MDT_MODULE: 553*c40fa3dcSJohn Baldwin if (dflag) { 554*c40fa3dcSJohn Baldwin printf(" module %s\n", cval); 555*c40fa3dcSJohn Baldwin } else { 556*c40fa3dcSJohn Baldwin record_int(MDT_MODULE); 557*c40fa3dcSJohn Baldwin record_string(cval); 558*c40fa3dcSJohn Baldwin record_string(kldname); 559*c40fa3dcSJohn Baldwin } 560*c40fa3dcSJohn Baldwin break; 561*c40fa3dcSJohn Baldwin case MDT_PNP_INFO: 562*c40fa3dcSJohn Baldwin check(EF_SEG_READ_REL(ef, data, sizeof(pnp), &pnp)); 563*c40fa3dcSJohn Baldwin check(EF_SEG_READ_STRING(ef, (Elf_Off)pnp.descr, sizeof(descr), descr)); 564*c40fa3dcSJohn Baldwin descr[sizeof(descr) - 1] = '\0'; 565*c40fa3dcSJohn Baldwin if (dflag) { 566*c40fa3dcSJohn Baldwin printf(" pnp info for bus %s format %s %d entries of %d bytes\n", 567*c40fa3dcSJohn Baldwin cval, descr, pnp.num_entry, pnp.entry_len); 568*c40fa3dcSJohn Baldwin } else { 569*c40fa3dcSJohn Baldwin record_pnp_info(ef, cval, &pnp, descr); 570*c40fa3dcSJohn Baldwin } 571493b2041SWarner Losh break; 5729c6f9240SPeter Wemm default: 5739f5529b4SRuslan Ermilov warnx("unknown metadata record %d in file %s", md->md_type, kldname); 5749c6f9240SPeter Wemm } 5759c6f9240SPeter Wemm if (!error) 5769c6f9240SPeter Wemm record_end(); 577e2d0802cSEd Maste return (error); 5789c6f9240SPeter Wemm } 5799c6f9240SPeter Wemm 5809c6f9240SPeter Wemm static int 5819c6f9240SPeter Wemm read_kld(char *filename, char *kldname) 5829c6f9240SPeter Wemm { 5839c6f9240SPeter Wemm struct mod_metadata md; 5849c6f9240SPeter Wemm struct elf_file ef; 5859c1fa7a4SConrad Meyer void **p; 586e2d0802cSEd Maste int error, eftype; 5879c1fa7a4SConrad Meyer long start, finish, entries, i; 588e2d0802cSEd Maste char cval[MAXMODNAME + 1]; 5899c6f9240SPeter Wemm 5909c6f9240SPeter Wemm if (verbose || dflag) 5919c6f9240SPeter Wemm printf("%s\n", filename); 5929c6f9240SPeter Wemm error = ef_open(filename, &ef, verbose); 593e2d0802cSEd Maste if (error != 0) { 5944a8b7e33SIan Dowse error = ef_obj_open(filename, &ef, verbose); 595e2d0802cSEd Maste if (error != 0) { 5969772dc2aSIan Dowse if (verbose) 5979772dc2aSIan Dowse warnc(error, "elf_open(%s)", filename); 598e2d0802cSEd Maste return (error); 5999772dc2aSIan Dowse } 6004a8b7e33SIan Dowse } 6019772dc2aSIan Dowse eftype = EF_GET_TYPE(&ef); 6029772dc2aSIan Dowse if (eftype != EFT_KLD && eftype != EFT_KERNEL) { 6039772dc2aSIan Dowse EF_CLOSE(&ef); 604e2d0802cSEd Maste return (0); 6059c6f9240SPeter Wemm } 6069c6f9240SPeter Wemm do { 6079772dc2aSIan Dowse check(EF_LOOKUP_SET(&ef, MDT_SETNAME, &start, &finish, 6089772dc2aSIan Dowse &entries)); 6099772dc2aSIan Dowse check(EF_SEG_READ_ENTRY_REL(&ef, start, sizeof(*p) * entries, 61076798703SDag-Erling Smørgrav (void *)&p)); 6119c1fa7a4SConrad Meyer /* 6129c1fa7a4SConrad Meyer * Do a first pass to find MDT_MODULE. It is required to be 6139c1fa7a4SConrad Meyer * ordered first in the output linker.hints stream because it 6149c1fa7a4SConrad Meyer * serves as an implicit record boundary between distinct klds 6159c1fa7a4SConrad Meyer * in the stream. Other MDTs only make sense in the context of 6169c1fa7a4SConrad Meyer * a specific MDT_MODULE. 6179c1fa7a4SConrad Meyer * 6189c1fa7a4SConrad Meyer * Some compilers (e.g., GCC 6.4.0 xtoolchain) or binutils 6199c1fa7a4SConrad Meyer * (e.g., GNU binutils 2.32 objcopy/ld.bfd) can reorder 6209c1fa7a4SConrad Meyer * MODULE_METADATA set entries relative to the source ordering. 6219c1fa7a4SConrad Meyer * This is permitted by the C standard; memory layout of 6229c1fa7a4SConrad Meyer * file-scope objects is left implementation-defined. There is 6239c1fa7a4SConrad Meyer * no requirement that source code ordering is retained. 6249c1fa7a4SConrad Meyer * 6259c1fa7a4SConrad Meyer * Handle that here by taking two passes to ensure MDT_MODULE 6269c1fa7a4SConrad Meyer * records are emitted to linker.hints before other MDT records 6279c1fa7a4SConrad Meyer * in the same kld. 6289c1fa7a4SConrad Meyer */ 6299c1fa7a4SConrad Meyer for (i = 0; i < entries; i++) { 6309c1fa7a4SConrad Meyer check(EF_SEG_READ_REL(&ef, (Elf_Off)p[i], sizeof(md), 6319772dc2aSIan Dowse &md)); 632da67e6e6SEd Maste check(EF_SEG_READ_STRING(&ef, (Elf_Off)md.md_cval, 6339772dc2aSIan Dowse sizeof(cval), cval)); 6349c1fa7a4SConrad Meyer if (md.md_type == MDT_MODULE) { 6359c1fa7a4SConrad Meyer parse_entry(&md, cval, &ef, kldname); 6369c1fa7a4SConrad Meyer break; 6379c1fa7a4SConrad Meyer } 6389c1fa7a4SConrad Meyer } 6399c1fa7a4SConrad Meyer if (error != 0) { 6409c1fa7a4SConrad Meyer warnc(error, "error while reading %s", filename); 6419c1fa7a4SConrad Meyer break; 6429c1fa7a4SConrad Meyer } 6439c1fa7a4SConrad Meyer 6449c1fa7a4SConrad Meyer /* 6459c1fa7a4SConrad Meyer * Second pass for all !MDT_MODULE entries. 6469c1fa7a4SConrad Meyer */ 6479c1fa7a4SConrad Meyer for (i = 0; i < entries; i++) { 6489c1fa7a4SConrad Meyer check(EF_SEG_READ_REL(&ef, (Elf_Off)p[i], sizeof(md), 6499c1fa7a4SConrad Meyer &md)); 6509c1fa7a4SConrad Meyer check(EF_SEG_READ_STRING(&ef, (Elf_Off)md.md_cval, 6519c1fa7a4SConrad Meyer sizeof(cval), cval)); 6529c1fa7a4SConrad Meyer if (md.md_type != MDT_MODULE) 6539c6f9240SPeter Wemm parse_entry(&md, cval, &ef, kldname); 6549c6f9240SPeter Wemm } 655e2d0802cSEd Maste if (error != 0) 6569c6f9240SPeter Wemm warnc(error, "error while reading %s", filename); 6579c1fa7a4SConrad Meyer free(p); 6589c6f9240SPeter Wemm } while(0); 6599772dc2aSIan Dowse EF_CLOSE(&ef); 660e2d0802cSEd Maste return (error); 6619c6f9240SPeter Wemm } 6629c6f9240SPeter Wemm 6639cb138bbSLuigi Rizzo /* 6649cb138bbSLuigi Rizzo * Create a temp file in directory root, make sure we don't 6659cb138bbSLuigi Rizzo * overflow the buffer for the destination name 6669cb138bbSLuigi Rizzo */ 6679cb138bbSLuigi Rizzo static FILE * 6689c6f9240SPeter Wemm maketempfile(char *dest, const char *root) 6699c6f9240SPeter Wemm { 6709c6f9240SPeter Wemm char *p; 6719cb138bbSLuigi Rizzo int n, fd; 6729c6f9240SPeter Wemm 6739cb138bbSLuigi Rizzo p = strrchr(root, '/'); 6749cb138bbSLuigi Rizzo n = p != NULL ? p - root + 1 : 0; 6759cb138bbSLuigi Rizzo if (snprintf(dest, MAXPATHLEN, "%.*slhint.XXXXXX", n, root) >= 6769cb138bbSLuigi Rizzo MAXPATHLEN) { 6779cb138bbSLuigi Rizzo errno = ENAMETOOLONG; 678e2d0802cSEd Maste return (NULL); 6799cb138bbSLuigi Rizzo } 6809c6f9240SPeter Wemm 6819ceddbd5SMarcel Moolenaar fd = mkstemp(dest); 6829cb138bbSLuigi Rizzo if (fd < 0) 683e2d0802cSEd Maste return (NULL); 684ddce5818SLuigi Rizzo fchmod(fd, 0644); /* nothing secret in the file */ 685e2d0802cSEd Maste return (fdopen(fd, "w+")); 6869c6f9240SPeter Wemm } 6879c6f9240SPeter Wemm 6889c6f9240SPeter Wemm static char xrefname[MAXPATHLEN], tempname[MAXPATHLEN]; 6899c6f9240SPeter Wemm 6909cb138bbSLuigi Rizzo static void 6919cb138bbSLuigi Rizzo usage(void) 6929cb138bbSLuigi Rizzo { 6939cb138bbSLuigi Rizzo 6949cb138bbSLuigi Rizzo fprintf(stderr, "%s\n", 6959cb138bbSLuigi Rizzo "usage: kldxref [-Rdv] [-f hintsfile] path ..." 6969cb138bbSLuigi Rizzo ); 6979cb138bbSLuigi Rizzo exit(1); 6989cb138bbSLuigi Rizzo } 6999cb138bbSLuigi Rizzo 7005d452ceaSJilles Tjoelker static int 7016d9cb20bSJilles Tjoelker compare(const FTSENT *const *a, const FTSENT *const *b) 7026d9cb20bSJilles Tjoelker { 703e2d0802cSEd Maste 7046d9cb20bSJilles Tjoelker if ((*a)->fts_info == FTS_D && (*b)->fts_info != FTS_D) 705e2d0802cSEd Maste return (1); 7066d9cb20bSJilles Tjoelker if ((*a)->fts_info != FTS_D && (*b)->fts_info == FTS_D) 707e2d0802cSEd Maste return (-1); 708e2d0802cSEd Maste return (strcmp((*a)->fts_name, (*b)->fts_name)); 7096d9cb20bSJilles Tjoelker } 7106d9cb20bSJilles Tjoelker 7116d9cb20bSJilles Tjoelker int 7129c6f9240SPeter Wemm main(int argc, char *argv[]) 7139c6f9240SPeter Wemm { 7149c6f9240SPeter Wemm FTS *ftsp; 7159c6f9240SPeter Wemm FTSENT *p; 716773c13c6SMina Galić char *dot = NULL; 7179c6f9240SPeter Wemm int opt, fts_options, ival; 718b7abc67eSMaxim Sobolev struct stat sb; 7199c6f9240SPeter Wemm 7209c6f9240SPeter Wemm fts_options = FTS_PHYSICAL; 7219c6f9240SPeter Wemm 7229c6f9240SPeter Wemm while ((opt = getopt(argc, argv, "Rdf:v")) != -1) { 7239c6f9240SPeter Wemm switch (opt) { 7249cb138bbSLuigi Rizzo case 'd': /* no hint file, only print on stdout */ 725e2d0802cSEd Maste dflag = true; 7269c6f9240SPeter Wemm break; 7279cb138bbSLuigi Rizzo case 'f': /* use this name instead of linker.hints */ 7289c6f9240SPeter Wemm xref_file = optarg; 7299c6f9240SPeter Wemm break; 7309c6f9240SPeter Wemm case 'v': 7319c6f9240SPeter Wemm verbose++; 7329c6f9240SPeter Wemm break; 7339cb138bbSLuigi Rizzo case 'R': /* recurse on directories */ 7349c6f9240SPeter Wemm fts_options |= FTS_COMFOLLOW; 7359c6f9240SPeter Wemm break; 7369c6f9240SPeter Wemm default: 7379c6f9240SPeter Wemm usage(); 7389c6f9240SPeter Wemm /* NOTREACHED */ 7399c6f9240SPeter Wemm } 7409c6f9240SPeter Wemm } 7419c6f9240SPeter Wemm if (argc - optind < 1) 7429c6f9240SPeter Wemm usage(); 7439c6f9240SPeter Wemm argc -= optind; 7449c6f9240SPeter Wemm argv += optind; 7459c6f9240SPeter Wemm 746b7abc67eSMaxim Sobolev if (stat(argv[0], &sb) != 0) 747b7abc67eSMaxim Sobolev err(1, "%s", argv[0]); 748d7751071SKonstantin Belousov if ((sb.st_mode & S_IFDIR) == 0 && !dflag) { 749b7abc67eSMaxim Sobolev errno = ENOTDIR; 750b7abc67eSMaxim Sobolev err(1, "%s", argv[0]); 751b7abc67eSMaxim Sobolev } 752b7abc67eSMaxim Sobolev 7536d9cb20bSJilles Tjoelker ftsp = fts_open(argv, fts_options, compare); 7549c6f9240SPeter Wemm if (ftsp == NULL) 7559c6f9240SPeter Wemm exit(1); 7569c6f9240SPeter Wemm 7579c6f9240SPeter Wemm for (;;) { 7589c6f9240SPeter Wemm p = fts_read(ftsp); 7599cb138bbSLuigi Rizzo if ((p == NULL || p->fts_info == FTS_D) && fxref) { 7609cb138bbSLuigi Rizzo /* close and rename the current hint file */ 7619c6f9240SPeter Wemm fclose(fxref); 7629ceddbd5SMarcel Moolenaar fxref = NULL; 763e2d0802cSEd Maste if (reccnt != 0) { 7649c6f9240SPeter Wemm rename(tempname, xrefname); 7659c6f9240SPeter Wemm } else { 7669cb138bbSLuigi Rizzo /* didn't find any entry, ignore this file */ 7679c6f9240SPeter Wemm unlink(tempname); 7689c6f9240SPeter Wemm unlink(xrefname); 7699c6f9240SPeter Wemm } 7709c6f9240SPeter Wemm } 7719c6f9240SPeter Wemm if (p == NULL) 7729c6f9240SPeter Wemm break; 7739cb138bbSLuigi Rizzo if (p->fts_info == FTS_D && !dflag) { 7749cb138bbSLuigi Rizzo /* visiting a new directory, create a new hint file */ 7759c6f9240SPeter Wemm snprintf(xrefname, sizeof(xrefname), "%s/%s", 7769c6f9240SPeter Wemm ftsp->fts_path, xref_file); 7779ceddbd5SMarcel Moolenaar fxref = maketempfile(tempname, ftsp->fts_path); 7789c6f9240SPeter Wemm if (fxref == NULL) 7799c6f9240SPeter Wemm err(1, "can't create %s", tempname); 7809c6f9240SPeter Wemm ival = 1; 7819c6f9240SPeter Wemm fwrite(&ival, sizeof(ival), 1, fxref); 7829c6f9240SPeter Wemm reccnt = 0; 7839c6f9240SPeter Wemm } 784773c13c6SMina Galić /* skip non-files.. */ 7859c6f9240SPeter Wemm if (p->fts_info != FTS_F) 7869c6f9240SPeter Wemm continue; 787773c13c6SMina Galić /* 788773c13c6SMina Galić * Skip files that generate errors like .debug, .symbol and .pkgsave 789773c13c6SMina Galić * by generally skipping all files with 2 dots. 790773c13c6SMina Galić */ 791773c13c6SMina Galić dot = strchr(p->fts_name, '.'); 792773c13c6SMina Galić if (dot && strchr(dot + 1, '.') != NULL) 7939f5529b4SRuslan Ermilov continue; 7949c6f9240SPeter Wemm read_kld(p->fts_path, p->fts_name); 7959c6f9240SPeter Wemm } 7969c6f9240SPeter Wemm fts_close(ftsp); 797e2d0802cSEd Maste return (0); 7989c6f9240SPeter Wemm } 799