1 /*- 2 * Copyright (c) 2013 Baptiste Daroussin <bapt@FreeBSD.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27 #include <sys/cdefs.h> 28 __FBSDID("$FreeBSD$"); 29 30 #include <sys/param.h> 31 #include <sys/sbuf.h> 32 #include <sys/elf_common.h> 33 #include <sys/endian.h> 34 35 #include <assert.h> 36 #include <bsdyml.h> 37 #include <ctype.h> 38 #include <err.h> 39 #include <errno.h> 40 #include <fcntl.h> 41 #include <gelf.h> 42 #include <inttypes.h> 43 #include <paths.h> 44 #include <stdbool.h> 45 #include <string.h> 46 #include <unistd.h> 47 48 #include "elf_tables.h" 49 #include "config.h" 50 51 #define roundup2(x, y) (((x)+((y)-1))&(~((y)-1))) /* if y is powers of two */ 52 53 struct config_entry { 54 uint8_t type; 55 const char *key; 56 const char *val; 57 char *value; 58 bool envset; 59 }; 60 61 static struct config_entry c[] = { 62 [PACKAGESITE] = { 63 PKG_CONFIG_STRING, 64 "PACKAGESITE", 65 "http://pkg.FreeBSD.org/${ABI}/latest", 66 NULL, 67 false, 68 }, 69 [ABI] = { 70 PKG_CONFIG_STRING, 71 "ABI", 72 NULL, 73 NULL, 74 false, 75 }, 76 [MIRROR_TYPE] = { 77 PKG_CONFIG_STRING, 78 "MIRROR_TYPE", 79 "SRV", 80 NULL, 81 false, 82 }, 83 [ASSUME_ALWAYS_YES] = { 84 PKG_CONFIG_BOOL, 85 "ASSUME_ALWAYS_YES", 86 "NO", 87 NULL, 88 false, 89 } 90 }; 91 92 static const char * 93 elf_corres_to_string(struct _elf_corres *m, int e) 94 { 95 int i; 96 97 for (i = 0; m[i].string != NULL; i++) 98 if (m[i].elf_nb == e) 99 return (m[i].string); 100 101 return ("unknown"); 102 } 103 104 static const char * 105 aeabi_parse_arm_attributes(void *data, size_t length) 106 { 107 uint32_t sect_len; 108 uint8_t *section = data; 109 110 #define MOVE(len) do { \ 111 assert(length >= (len)); \ 112 section += (len); \ 113 length -= (len); \ 114 } while (0) 115 116 if (length == 0 || *section != 'A') 117 return (NULL); 118 119 MOVE(1); 120 121 /* Read the section length */ 122 if (length < sizeof(sect_len)) 123 return (NULL); 124 125 memcpy(§_len, section, sizeof(sect_len)); 126 127 /* 128 * The section length should be no longer than the section it is within 129 */ 130 if (sect_len > length) 131 return (NULL); 132 133 MOVE(sizeof(sect_len)); 134 135 /* Skip the vendor name */ 136 while (length != 0) { 137 if (*section == '\0') 138 break; 139 MOVE(1); 140 } 141 if (length == 0) 142 return (NULL); 143 MOVE(1); 144 145 while (length != 0) { 146 uint32_t tag_length; 147 148 switch(*section) { 149 case 1: /* Tag_File */ 150 MOVE(1); 151 if (length < sizeof(tag_length)) 152 return (NULL); 153 memcpy(&tag_length, section, sizeof(tag_length)); 154 break; 155 case 2: /* Tag_Section */ 156 case 3: /* Tag_Symbol */ 157 default: 158 return (NULL); 159 } 160 /* At least space for the tag and size */ 161 if (tag_length <= 5) 162 return (NULL); 163 tag_length--; 164 /* Check the tag fits */ 165 if (tag_length > length) 166 return (NULL); 167 168 #define MOVE_TAG(len) do { \ 169 assert(tag_length >= (len)); \ 170 MOVE(len); \ 171 tag_length -= (len); \ 172 } while(0) 173 174 MOVE(sizeof(tag_length)); 175 tag_length -= sizeof(tag_length); 176 177 while (tag_length != 0) { 178 uint8_t tag; 179 180 assert(tag_length >= length); 181 182 tag = *section; 183 MOVE_TAG(1); 184 185 /* 186 * These tag values come from: 187 * 188 * Addenda to, and Errata in, the ABI for the 189 * ARM Architecture. Release 2.08, section 2.3. 190 */ 191 if (tag == 6) { /* == Tag_CPU_arch */ 192 uint8_t val; 193 194 val = *section; 195 /* 196 * We don't support values that require 197 * more than one byte. 198 */ 199 if (val & (1 << 7)) 200 return (NULL); 201 202 /* We have an ARMv4 or ARMv5 */ 203 if (val <= 5) 204 return ("arm"); 205 else /* We have an ARMv6+ */ 206 return ("armv6"); 207 } else if (tag == 4 || tag == 5 || tag == 32 || 208 tag == 65 || tag == 67) { 209 while (*section != '\0' && length != 0) 210 MOVE_TAG(1); 211 if (tag_length == 0) 212 return (NULL); 213 /* Skip the last byte */ 214 MOVE_TAG(1); 215 } else if ((tag >= 7 && tag <= 31) || tag == 34 || 216 tag == 36 || tag == 38 || tag == 42 || tag == 44 || 217 tag == 64 || tag == 66 || tag == 68 || tag == 70) { 218 /* Skip the uleb128 data */ 219 while (*section & (1 << 7) && length != 0) 220 MOVE_TAG(1); 221 if (tag_length == 0) 222 return (NULL); 223 /* Skip the last byte */ 224 MOVE_TAG(1); 225 } else 226 return (NULL); 227 #undef MOVE_TAG 228 } 229 230 break; 231 } 232 return (NULL); 233 #undef MOVE 234 } 235 236 static int 237 pkg_get_myabi(char *dest, size_t sz) 238 { 239 Elf *elf; 240 Elf_Data *data; 241 Elf_Note note; 242 Elf_Scn *scn; 243 char *src, *osname; 244 const char *arch, *abi, *fpu, *endian_corres_str; 245 const char *wordsize_corres_str; 246 GElf_Ehdr elfhdr; 247 GElf_Shdr shdr; 248 int fd, i, ret; 249 uint32_t version; 250 251 version = 0; 252 ret = -1; 253 scn = NULL; 254 abi = NULL; 255 256 if (elf_version(EV_CURRENT) == EV_NONE) { 257 warnx("ELF library initialization failed: %s", 258 elf_errmsg(-1)); 259 return (-1); 260 } 261 262 if ((fd = open(_PATH_BSHELL, O_RDONLY)) < 0) { 263 warn("open()"); 264 return (-1); 265 } 266 267 if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) { 268 ret = -1; 269 warnx("elf_begin() failed: %s.", elf_errmsg(-1)); 270 goto cleanup; 271 } 272 273 if (gelf_getehdr(elf, &elfhdr) == NULL) { 274 ret = -1; 275 warn("getehdr() failed: %s.", elf_errmsg(-1)); 276 goto cleanup; 277 } 278 while ((scn = elf_nextscn(elf, scn)) != NULL) { 279 if (gelf_getshdr(scn, &shdr) != &shdr) { 280 ret = -1; 281 warn("getshdr() failed: %s.", elf_errmsg(-1)); 282 goto cleanup; 283 } 284 285 if (shdr.sh_type == SHT_NOTE) 286 break; 287 } 288 289 if (scn == NULL) { 290 ret = -1; 291 warn("failed to get the note section"); 292 goto cleanup; 293 } 294 295 data = elf_getdata(scn, NULL); 296 src = data->d_buf; 297 for (;;) { 298 memcpy(¬e, src, sizeof(Elf_Note)); 299 src += sizeof(Elf_Note); 300 if (note.n_type == NT_VERSION) 301 break; 302 src += note.n_namesz + note.n_descsz; 303 } 304 osname = src; 305 src += roundup2(note.n_namesz, 4); 306 if (elfhdr.e_ident[EI_DATA] == ELFDATA2MSB) 307 version = be32dec(src); 308 else 309 version = le32dec(src); 310 311 for (i = 0; osname[i] != '\0'; i++) 312 osname[i] = (char)tolower(osname[i]); 313 314 wordsize_corres_str = elf_corres_to_string(wordsize_corres, 315 (int)elfhdr.e_ident[EI_CLASS]); 316 317 arch = elf_corres_to_string(mach_corres, (int) elfhdr.e_machine); 318 319 snprintf(dest, sz, "%s:%d", 320 osname, version / 100000); 321 322 ret = 0; 323 324 switch (elfhdr.e_machine) { 325 case EM_ARM: 326 endian_corres_str = elf_corres_to_string(endian_corres, 327 (int)elfhdr.e_ident[EI_DATA]); 328 329 /* FreeBSD doesn't support the hard-float ABI yet */ 330 fpu = "softfp"; 331 if ((elfhdr.e_flags & 0xFF000000) != 0) { 332 const char *sh_name = NULL; 333 size_t shstrndx; 334 335 /* This is an EABI file, the conformance level is set */ 336 abi = "eabi"; 337 /* Find which TARGET_ARCH we are building for. */ 338 elf_getshdrstrndx(elf, &shstrndx); 339 while ((scn = elf_nextscn(elf, scn)) != NULL) { 340 sh_name = NULL; 341 if (gelf_getshdr(scn, &shdr) != &shdr) { 342 scn = NULL; 343 break; 344 } 345 346 sh_name = elf_strptr(elf, shstrndx, 347 shdr.sh_name); 348 if (sh_name == NULL) 349 continue; 350 if (strcmp(".ARM.attributes", sh_name) == 0) 351 break; 352 } 353 if (scn != NULL && sh_name != NULL) { 354 data = elf_getdata(scn, NULL); 355 /* 356 * Prior to FreeBSD 10.0 libelf would return 357 * NULL from elf_getdata on the .ARM.attributes 358 * section. As this was the first release to 359 * get armv6 support assume a NULL value means 360 * arm. 361 * 362 * This assumption can be removed when 9.x 363 * is unsupported. 364 */ 365 if (data != NULL) { 366 arch = aeabi_parse_arm_attributes( 367 data->d_buf, data->d_size); 368 if (arch == NULL) { 369 ret = 1; 370 warn("unknown ARM ARCH"); 371 goto cleanup; 372 } 373 } 374 } else { 375 ret = 1; 376 warn("Unable to find the .ARM.attributes " 377 "section"); 378 goto cleanup; 379 } 380 } else if (elfhdr.e_ident[EI_OSABI] != ELFOSABI_NONE) { 381 /* 382 * EABI executables all have this field set to 383 * ELFOSABI_NONE, therefore it must be an oabi file. 384 */ 385 abi = "oabi"; 386 } else { 387 ret = 1; 388 warn("unknown ARM ABI"); 389 goto cleanup; 390 } 391 snprintf(dest + strlen(dest), sz - strlen(dest), 392 ":%s:%s:%s:%s:%s", arch, wordsize_corres_str, 393 endian_corres_str, abi, fpu); 394 break; 395 case EM_MIPS: 396 /* 397 * this is taken from binutils sources: 398 * include/elf/mips.h 399 * mapping is figured out from binutils: 400 * gas/config/tc-mips.c 401 */ 402 switch (elfhdr.e_flags & EF_MIPS_ABI) { 403 case E_MIPS_ABI_O32: 404 abi = "o32"; 405 break; 406 case E_MIPS_ABI_N32: 407 abi = "n32"; 408 break; 409 default: 410 if (elfhdr.e_ident[EI_DATA] == 411 ELFCLASS32) 412 abi = "o32"; 413 else if (elfhdr.e_ident[EI_DATA] == 414 ELFCLASS64) 415 abi = "n64"; 416 break; 417 } 418 endian_corres_str = elf_corres_to_string(endian_corres, 419 (int)elfhdr.e_ident[EI_DATA]); 420 421 snprintf(dest + strlen(dest), sz - strlen(dest), ":%s:%s:%s:%s", 422 arch, wordsize_corres_str, endian_corres_str, abi); 423 break; 424 default: 425 snprintf(dest + strlen(dest), sz - strlen(dest), ":%s:%s", 426 arch, wordsize_corres_str); 427 } 428 429 cleanup: 430 if (elf != NULL) 431 elf_end(elf); 432 433 close(fd); 434 return (ret); 435 } 436 437 static void 438 subst_packagesite(const char *abi) 439 { 440 struct sbuf *newval; 441 const char *variable_string; 442 const char *oldval; 443 444 if (c[PACKAGESITE].value != NULL) 445 oldval = c[PACKAGESITE].value; 446 else 447 oldval = c[PACKAGESITE].val; 448 449 if ((variable_string = strstr(oldval, "${ABI}")) == NULL) 450 return; 451 452 newval = sbuf_new_auto(); 453 sbuf_bcat(newval, oldval, variable_string - oldval); 454 sbuf_cat(newval, abi); 455 sbuf_cat(newval, variable_string + strlen("${ABI}")); 456 sbuf_finish(newval); 457 458 free(c[PACKAGESITE].value); 459 c[PACKAGESITE].value = strdup(sbuf_data(newval)); 460 } 461 462 static void 463 config_parse(yaml_document_t *doc, yaml_node_t *node) 464 { 465 yaml_node_pair_t *pair; 466 yaml_node_t *key, *val; 467 struct sbuf *buf = sbuf_new_auto(); 468 int i; 469 size_t j; 470 471 pair = node->data.mapping.pairs.start; 472 473 while (pair < node->data.mapping.pairs.top) { 474 key = yaml_document_get_node(doc, pair->key); 475 val = yaml_document_get_node(doc, pair->value); 476 477 /* 478 * ignoring silently empty keys can be empty lines 479 * or user mistakes 480 */ 481 if (key->data.scalar.length <= 0) { 482 ++pair; 483 continue; 484 } 485 486 /* 487 * silently skip on purpose to allow user to leave 488 * empty lines without complaining 489 */ 490 if (val->type == YAML_NO_NODE || 491 (val->type == YAML_SCALAR_NODE && 492 val->data.scalar.length <= 0)) { 493 ++pair; 494 continue; 495 } 496 497 sbuf_clear(buf); 498 for (j = 0; j < strlen(key->data.scalar.value); ++j) 499 sbuf_putc(buf, toupper(key->data.scalar.value[j])); 500 501 sbuf_finish(buf); 502 for (i = 0; i < CONFIG_SIZE; i++) { 503 if (strcmp(sbuf_data(buf), c[i].key) == 0) 504 break; 505 } 506 507 if (i == CONFIG_SIZE) { 508 ++pair; 509 continue; 510 } 511 512 /* env has priority over config file */ 513 if (c[i].envset) { 514 ++pair; 515 continue; 516 } 517 518 c[i].value = strdup(val->data.scalar.value); 519 ++pair; 520 } 521 522 sbuf_delete(buf); 523 } 524 525 int 526 config_init(void) 527 { 528 FILE *fp; 529 yaml_parser_t parser; 530 yaml_document_t doc; 531 yaml_node_t *node; 532 const char *val; 533 int i; 534 const char *localbase; 535 char confpath[MAXPATHLEN]; 536 char abi[BUFSIZ]; 537 538 for (i = 0; i < CONFIG_SIZE; i++) { 539 val = getenv(c[i].key); 540 if (val != NULL) { 541 c[i].val = val; 542 c[i].envset = true; 543 } 544 } 545 546 localbase = getenv("LOCALBASE") ? getenv("LOCALBASE") : _LOCALBASE; 547 snprintf(confpath, sizeof(confpath), "%s/etc/pkg.conf", localbase); 548 549 if ((fp = fopen(confpath, "r")) == NULL) { 550 if (errno != ENOENT) 551 err(EXIT_FAILURE, "Unable to open configuration file %s", confpath); 552 /* no configuration present */ 553 goto finalize; 554 } 555 556 yaml_parser_initialize(&parser); 557 yaml_parser_set_input_file(&parser, fp); 558 yaml_parser_load(&parser, &doc); 559 560 node = yaml_document_get_root_node(&doc); 561 562 if (node != NULL) { 563 if (node->type != YAML_MAPPING_NODE) 564 warnx("Invalid configuration format, ignoring the configuration file"); 565 else 566 config_parse(&doc, node); 567 } else { 568 warnx("Invalid configuration format, ignoring the configuration file"); 569 } 570 571 yaml_document_delete(&doc); 572 yaml_parser_delete(&parser); 573 574 finalize: 575 if (c[ABI].val == NULL && c[ABI].value == NULL) { 576 if (pkg_get_myabi(abi, BUFSIZ) != 0) 577 errx(EXIT_FAILURE, "Failed to determine the system ABI"); 578 c[ABI].val = abi; 579 } 580 581 subst_packagesite(c[ABI].value != NULL ? c[ABI].value : c[ABI].val); 582 583 return (0); 584 } 585 586 int 587 config_string(pkg_config_key k, const char **val) 588 { 589 if (c[k].type != PKG_CONFIG_STRING) 590 return (-1); 591 592 if (c[k].value != NULL) 593 *val = c[k].value; 594 else 595 *val = c[k].val; 596 597 return (0); 598 } 599 600 int 601 config_bool(pkg_config_key k, bool *val) 602 { 603 const char *value; 604 605 if (c[k].type != PKG_CONFIG_BOOL) 606 return (-1); 607 608 *val = false; 609 610 if (c[k].value != NULL) 611 value = c[k].value; 612 else 613 value = c[k].val; 614 615 if (strcasecmp(value, "true") == 0 || 616 strcasecmp(value, "yes") == 0 || 617 strcasecmp(value, "on") == 0 || 618 *value == '1') 619 *val = true; 620 621 return (0); 622 } 623 624 void 625 config_finish(void) { 626 int i; 627 628 for (i = 0; i < CONFIG_SIZE; i++) 629 free(c[i].value); 630 } 631