1 /* opkg.c - the opkg package management system 2 3 Thomas Wood <thomas@openedhand.com> 4 5 Copyright (C) 2008 OpenMoko Inc 6 7 This program is free software; you can redistribute it and/or 8 modify it under the terms of the GNU General Public License as 9 published by the Free Software Foundation; either version 2, or (at 10 your option) any later version. 11 12 This program is distributed in the hope that it will be useful, but 13 WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 General Public License for more details. 16 */ 17 18 #include <stdio.h> 19 #include <unistd.h> 20 #include <fnmatch.h> 21 22 #include "opkg.h" 23 #include "opkg_conf.h" 24 25 #include "opkg_install.h" 26 #include "opkg_configure.h" 27 #include "opkg_download.h" 28 #include "opkg_remove.h" 29 #include "opkg_upgrade.h" 30 31 #include "sprintf_alloc.h" 32 #include "file_util.h" 33 34 #include <libbb/libbb.h> 35 36 #define opkg_assert(expr) if (!(expr)) { \ 37 printf ("opkg: file %s: line %d (%s): Assertation '%s' failed",\ 38 __FILE__, __LINE__, __PRETTY_FUNCTION__, # expr); abort (); } 39 40 #define progress(d, p) d.percentage = p; if (progress_callback) progress_callback (&d, user_data); 41 42 /** Private Functions ***/ 43 44 static int opkg_configure_packages(char *pkg_name) 45 { 46 pkg_vec_t *all; 47 int i; 48 pkg_t *pkg; 49 int r, err = 0; 50 51 all = pkg_vec_alloc(); 52 pkg_hash_fetch_available(all); 53 54 for (i = 0; i < all->len; i++) { 55 pkg = all->pkgs[i]; 56 57 if (pkg_name && fnmatch(pkg_name, pkg->name, 0)) 58 continue; 59 60 if (pkg->state_status == SS_UNPACKED) { 61 r = opkg_configure(pkg); 62 if (r == 0) { 63 pkg->state_status = SS_INSTALLED; 64 pkg->parent->state_status = SS_INSTALLED; 65 pkg->state_flag &= ~SF_PREFER; 66 } else { 67 if (!err) 68 err = r; 69 } 70 } 71 } 72 73 pkg_vec_free(all); 74 return err; 75 } 76 77 static struct opkg_conf saved_conf; 78 /*** Public API ***/ 79 80 int opkg_new() 81 { 82 saved_conf = *conf; 83 84 if (opkg_conf_init()) 85 goto err0; 86 87 if (opkg_conf_load()) 88 goto err0; 89 90 if (pkg_hash_load_feeds(0, NULL, NULL)) 91 goto err1; 92 93 if (pkg_hash_load_status_files(NULL, NULL)) 94 goto err1; 95 96 return 0; 97 98 err1: 99 pkg_hash_deinit(); 100 err0: 101 opkg_conf_deinit(); 102 return -1; 103 } 104 105 void opkg_free(void) 106 { 107 opkg_conf_deinit(); 108 } 109 110 int opkg_re_read_config_files(void) 111 { 112 opkg_free(); 113 *conf = saved_conf; 114 return opkg_new(); 115 } 116 117 void opkg_get_option(char *option, void **value) 118 { 119 int i = 0; 120 extern opkg_option_t options[]; 121 122 /* look up the option 123 * TODO: this would be much better as a hash table 124 */ 125 while (options[i].name) { 126 if (strcmp(options[i].name, option) != 0) { 127 i++; 128 continue; 129 } 130 } 131 132 /* get the option */ 133 switch (options[i].type) { 134 case OPKG_OPT_TYPE_BOOL: 135 *((int *)value) = *((int *)options[i].value); 136 return; 137 138 case OPKG_OPT_TYPE_INT: 139 *((int *)value) = *((int *)options[i].value); 140 return; 141 142 case OPKG_OPT_TYPE_STRING: 143 *((char **)value) = xstrdup(options[i].value); 144 return; 145 } 146 147 } 148 149 void opkg_set_option(char *option, void *value) 150 { 151 int i = 0, found = 0; 152 extern opkg_option_t options[]; 153 154 opkg_assert(option != NULL); 155 opkg_assert(value != NULL); 156 157 /* look up the option 158 * TODO: this would be much better as a hash table 159 */ 160 while (options[i].name) { 161 if (strcmp(options[i].name, option) == 0) { 162 found = 1; 163 break; 164 } 165 i++; 166 } 167 168 if (!found) { 169 opkg_msg(ERROR, "Invalid option: %s\n", option); 170 return; 171 } 172 173 /* set the option */ 174 switch (options[i].type) { 175 case OPKG_OPT_TYPE_BOOL: 176 if (*((int *)value) == 0) 177 *((int *)options[i].value) = 0; 178 else 179 *((int *)options[i].value) = 1; 180 return; 181 182 case OPKG_OPT_TYPE_INT: 183 *((int *)options[i].value) = *((int *)value); 184 return; 185 186 case OPKG_OPT_TYPE_STRING: 187 *((char **)options[i].value) = xstrdup(value); 188 return; 189 } 190 191 } 192 193 /** 194 * @brief libopkg API: Install package 195 * @param package_name The name of package in which is going to install 196 * @param progress_callback The callback function that report the status to caller. 197 */ 198 int 199 opkg_install_package(const char *package_name, 200 opkg_progress_callback_t progress_callback, 201 void *user_data) 202 { 203 int err; 204 char *stripped_filename, *local_filename; 205 opkg_progress_data_t pdata; 206 pkg_t *old, *new; 207 pkg_vec_t *deps, *all; 208 int i; 209 char **unresolved = NULL; 210 const char *filename; 211 212 opkg_assert(package_name != NULL); 213 214 /* ... */ 215 pkg_info_preinstall_check(); 216 217 /* check to ensure package is not already installed */ 218 old = pkg_hash_fetch_installed_by_name(package_name); 219 if (old) { 220 opkg_msg(ERROR, "Package %s is already installed\n", 221 package_name); 222 return -1; 223 } 224 225 new = pkg_hash_fetch_best_installation_candidate_by_name(package_name); 226 if (!new) { 227 opkg_msg(ERROR, "Couldn't find package %s\n", package_name); 228 return -1; 229 } 230 231 new->state_flag |= SF_USER; 232 233 pdata.action = -1; 234 pdata.pkg = new; 235 236 progress(pdata, 0); 237 238 /* find dependancies and download them */ 239 deps = pkg_vec_alloc(); 240 /* this function does not return the original package, so we insert it later */ 241 pkg_hash_fetch_unsatisfied_dependencies(new, deps, &unresolved, 0); 242 if (unresolved) { 243 char **tmp = unresolved; 244 opkg_msg(ERROR, "Couldn't satisfy the following dependencies" 245 " for %s:\n", package_name); 246 while (*tmp) { 247 opkg_msg(ERROR, "\t%s", *tmp); 248 free(*tmp); 249 tmp++; 250 } 251 free(unresolved); 252 pkg_vec_free(deps); 253 opkg_message(ERROR, "\n"); 254 return -1; 255 } 256 257 /* insert the package we are installing so that we download it */ 258 pkg_vec_insert(deps, new); 259 260 /* download package and dependencies */ 261 for (i = 0; i < deps->len; i++) { 262 pkg_t *pkg; 263 char *url, *urlencoded_path; 264 265 pkg = deps->pkgs[i]; 266 if (pkg_get_string(pkg, PKG_LOCAL_FILENAME)) 267 continue; 268 269 pdata.pkg = pkg; 270 pdata.action = OPKG_DOWNLOAD; 271 272 if (pkg->src == NULL) { 273 opkg_msg(ERROR, "Package %s not available from any " 274 "configured src\n", package_name); 275 return -1; 276 } 277 278 filename = pkg_get_string(pkg, PKG_FILENAME); 279 urlencoded_path = urlencode_path(filename); 280 sprintf_alloc(&url, "%s/%s", pkg->src->value, urlencoded_path); 281 free(urlencoded_path); 282 283 /* Get the filename part, without any directory */ 284 stripped_filename = strrchr(filename, '/'); 285 if (!stripped_filename) 286 stripped_filename = (char *)filename; 287 288 sprintf_alloc(&local_filename, "%s/%s", conf->tmp_dir, 289 stripped_filename); 290 291 pkg_set_string(pkg, PKG_LOCAL_FILENAME, local_filename); 292 293 err = opkg_download(url, local_filename, 0); 294 free(url); 295 296 if (err) { 297 pkg_vec_free(deps); 298 return -1; 299 } 300 301 } 302 pkg_vec_free(deps); 303 304 /* clear depenacy checked marks, left by pkg_hash_fetch_unsatisfied_dependencies */ 305 all = pkg_vec_alloc(); 306 pkg_hash_fetch_available(all); 307 for (i = 0; i < all->len; i++) { 308 all->pkgs[i]->parent->dependencies_checked = 0; 309 } 310 pkg_vec_free(all); 311 312 /* 75% of "install" progress is for downloading */ 313 pdata.pkg = new; 314 pdata.action = OPKG_INSTALL; 315 progress(pdata, 75); 316 317 /* unpack the package */ 318 err = opkg_install_pkg(new, 0); 319 320 if (err) { 321 return -1; 322 } 323 324 progress(pdata, 75); 325 326 /* run configure scripts, etc. */ 327 err = opkg_configure_packages(NULL); 328 if (err) { 329 return -1; 330 } 331 332 /* write out status files and file lists */ 333 opkg_conf_write_status_files(); 334 pkg_write_changed_filelists(); 335 336 progress(pdata, 100); 337 return 0; 338 } 339 340 int 341 opkg_remove_package(const char *package_name, 342 opkg_progress_callback_t progress_callback, void *user_data) 343 { 344 int err; 345 pkg_t *pkg = NULL; 346 pkg_t *pkg_to_remove; 347 opkg_progress_data_t pdata; 348 349 opkg_assert(package_name != NULL); 350 351 pkg_info_preinstall_check(); 352 353 pkg = pkg_hash_fetch_installed_by_name(package_name); 354 355 if (pkg == NULL || pkg->state_status == SS_NOT_INSTALLED) { 356 opkg_msg(ERROR, "Package %s not installed\n", package_name); 357 return -1; 358 } 359 360 pdata.action = OPKG_REMOVE; 361 pdata.pkg = pkg; 362 progress(pdata, 0); 363 364 if (conf->restrict_to_default_dest) { 365 pkg_to_remove = pkg_hash_fetch_installed_by_name_dest(pkg->name, 366 conf-> 367 default_dest); 368 } else { 369 pkg_to_remove = pkg_hash_fetch_installed_by_name(pkg->name); 370 } 371 372 progress(pdata, 75); 373 374 err = opkg_remove_pkg(pkg_to_remove, 0); 375 376 /* write out status files and file lists */ 377 opkg_conf_write_status_files(); 378 pkg_write_changed_filelists(); 379 380 progress(pdata, 100); 381 return (err) ? -1 : 0; 382 } 383 384 int 385 opkg_upgrade_package(const char *package_name, 386 opkg_progress_callback_t progress_callback, 387 void *user_data) 388 { 389 int err; 390 pkg_t *pkg; 391 opkg_progress_data_t pdata; 392 393 opkg_assert(package_name != NULL); 394 395 pkg_info_preinstall_check(); 396 397 if (conf->restrict_to_default_dest) { 398 pkg = pkg_hash_fetch_installed_by_name_dest(package_name, 399 conf->default_dest); 400 } else { 401 pkg = pkg_hash_fetch_installed_by_name(package_name); 402 } 403 404 if (!pkg) { 405 opkg_msg(ERROR, "Package %s not installed\n", package_name); 406 return -1; 407 } 408 409 pdata.action = OPKG_INSTALL; 410 pdata.pkg = pkg; 411 progress(pdata, 0); 412 413 err = opkg_upgrade_pkg(pkg); 414 if (err) { 415 return -1; 416 } 417 progress(pdata, 75); 418 419 err = opkg_configure_packages(NULL); 420 if (err) { 421 return -1; 422 } 423 424 /* write out status files and file lists */ 425 opkg_conf_write_status_files(); 426 pkg_write_changed_filelists(); 427 428 progress(pdata, 100); 429 return 0; 430 } 431 432 int 433 opkg_upgrade_all(opkg_progress_callback_t progress_callback, void *user_data) 434 { 435 pkg_vec_t *installed; 436 int err = 0; 437 int i; 438 pkg_t *pkg; 439 opkg_progress_data_t pdata; 440 441 pdata.action = OPKG_INSTALL; 442 pdata.pkg = NULL; 443 444 progress(pdata, 0); 445 446 installed = pkg_vec_alloc(); 447 pkg_info_preinstall_check(); 448 449 pkg_hash_fetch_all_installed(installed); 450 for (i = 0; i < installed->len; i++) { 451 pkg = installed->pkgs[i]; 452 453 pdata.pkg = pkg; 454 progress(pdata, 99 * i / installed->len); 455 456 err += opkg_upgrade_pkg(pkg); 457 } 458 pkg_vec_free(installed); 459 460 if (err) 461 return 1; 462 463 err = opkg_configure_packages(NULL); 464 if (err) 465 return 1; 466 467 /* write out status files and file lists */ 468 opkg_conf_write_status_files(); 469 pkg_write_changed_filelists(); 470 471 pdata.pkg = NULL; 472 progress(pdata, 100); 473 return 0; 474 } 475 476 int 477 opkg_update_package_lists(opkg_progress_callback_t progress_callback, 478 void *user_data) 479 { 480 char *tmp; 481 int err, result = 0; 482 char *lists_dir; 483 pkg_src_list_elt_t *iter; 484 pkg_src_t *src; 485 int sources_list_count, sources_done; 486 opkg_progress_data_t pdata; 487 488 pdata.action = OPKG_DOWNLOAD; 489 pdata.pkg = NULL; 490 progress(pdata, 0); 491 492 sprintf_alloc(&lists_dir, "%s", (conf->restrict_to_default_dest) 493 ? conf->default_dest->lists_dir : conf->lists_dir); 494 495 if (!file_is_dir(lists_dir)) { 496 if (file_exists(lists_dir)) { 497 opkg_msg(ERROR, "%s is not a directory\n", lists_dir); 498 free(lists_dir); 499 return 1; 500 } 501 502 err = file_mkdir_hier(lists_dir, 0755); 503 if (err) { 504 opkg_msg(ERROR, "Couldn't create lists_dir %s\n", 505 lists_dir); 506 free(lists_dir); 507 return 1; 508 } 509 } 510 511 sprintf_alloc(&tmp, "%s/update-XXXXXX", conf->tmp_dir); 512 if (mkdtemp(tmp) == NULL) { 513 opkg_perror(ERROR, "Coundn't create temporary directory %s", 514 tmp); 515 free(lists_dir); 516 free(tmp); 517 return 1; 518 } 519 520 /* count the number of sources so we can give some progress updates */ 521 sources_list_count = 0; 522 sources_done = 0; 523 list_for_each_entry(iter, &conf->pkg_src_list.head, node) { 524 sources_list_count++; 525 } 526 527 list_for_each_entry(iter, &conf->pkg_src_list.head, node) { 528 char *url, *list_file_name = NULL; 529 530 src = (pkg_src_t *) iter->data; 531 532 sprintf_alloc(&url, "%s/%s", src->value, 533 src->gzip ? "Packages.gz" : "Packages"); 534 535 sprintf_alloc(&list_file_name, "%s/%s", lists_dir, src->name); 536 537 if (opkg_download(url, list_file_name, 0)) { 538 opkg_msg(ERROR, "Couldn't retrieve %s\n", url); 539 result = -1; 540 } 541 free(url); 542 543 #if defined(HAVE_USIGN) 544 if (conf->check_signature) { 545 char *sig_file_name; 546 /* download detached signitures to verify the package lists */ 547 /* get the url for the sig file */ 548 sprintf_alloc(&url, "%s/%s", src->value, 549 "Packages.sig"); 550 551 /* create filename for signature */ 552 sprintf_alloc(&sig_file_name, "%s/%s.sig", lists_dir, 553 src->name); 554 555 /* make sure there is no existing signature file */ 556 unlink(sig_file_name); 557 558 err = opkg_download(url, sig_file_name, 0); 559 if (err) { 560 opkg_msg(ERROR, "Couldn't retrieve %s\n", url); 561 } else { 562 int err; 563 err = opkg_verify_file(list_file_name, 564 sig_file_name); 565 if (err == 0) { 566 opkg_msg(INFO, "Signature check " 567 "passed for %s", 568 list_file_name); 569 } else { 570 opkg_msg(ERROR, "Signature check " 571 "failed for %s", 572 list_file_name); 573 } 574 } 575 free(sig_file_name); 576 free(url); 577 } 578 #else 579 opkg_msg(INFO, "Signature check skipped for %s as GPG support" 580 " has not been enabled in this build\n", 581 list_file_name); 582 #endif 583 free(list_file_name); 584 585 sources_done++; 586 progress(pdata, 100 * sources_done / sources_list_count); 587 } 588 589 rmdir(tmp); 590 free(tmp); 591 free(lists_dir); 592 593 /* Now re-read the package lists to update package hash tables. */ 594 opkg_re_read_config_files(); 595 596 return result; 597 } 598 599 static int pkg_compare_names_and_version(const void *a0, const void *b0) 600 { 601 const pkg_t *a = *(const pkg_t **)a0; 602 const pkg_t *b = *(const pkg_t **)b0; 603 int ret; 604 605 ret = strcmp(a->name, b->name); 606 607 if (ret == 0) 608 ret = pkg_compare_versions(a, b); 609 610 return ret; 611 } 612 613 int opkg_list_packages(opkg_package_callback_t callback, void *user_data) 614 { 615 pkg_vec_t *all; 616 int i; 617 618 opkg_assert(callback); 619 620 all = pkg_vec_alloc(); 621 pkg_hash_fetch_available(all); 622 623 pkg_vec_sort(all, pkg_compare_names_and_version); 624 625 for (i = 0; i < all->len; i++) { 626 pkg_t *pkg; 627 628 pkg = all->pkgs[i]; 629 630 callback(pkg, user_data); 631 } 632 633 pkg_vec_free(all); 634 635 return 0; 636 } 637 638 int 639 opkg_list_upgradable_packages(opkg_package_callback_t callback, void *user_data) 640 { 641 struct active_list *head; 642 struct active_list *node; 643 pkg_t *old = NULL, *new = NULL; 644 645 opkg_assert(callback); 646 647 /* ensure all data is valid */ 648 pkg_info_preinstall_check(); 649 650 head = prepare_upgrade_list(); 651 for (node = active_list_next(head, head); node; 652 node = active_list_next(head, node)) { 653 old = node->pkg; 654 new = 655 pkg_hash_fetch_best_installation_candidate_by_name(old-> 656 name); 657 if (new == NULL) 658 continue; 659 callback(new, user_data); 660 } 661 active_list_head_delete(head); 662 return 0; 663 } 664 665 pkg_t *opkg_find_package(const char *name, const char *ver, const char *arch, 666 const char *repo) 667 { 668 int pkg_found = 0; 669 pkg_t *pkg = NULL; 670 pkg_vec_t *all; 671 int i; 672 #define sstrcmp(x,y) (x && y) ? strcmp (x, y) : 0 673 674 all = pkg_vec_alloc(); 675 pkg_hash_fetch_available(all); 676 for (i = 0; i < all->len; i++) { 677 char *pkgv; 678 679 pkg = all->pkgs[i]; 680 681 /* check name */ 682 if (sstrcmp(pkg->name, name)) 683 continue; 684 685 /* check version */ 686 pkgv = pkg_version_str_alloc(pkg); 687 if (sstrcmp(pkgv, ver)) { 688 free(pkgv); 689 continue; 690 } 691 free(pkgv); 692 693 /* check architecture */ 694 if (arch) { 695 if (sstrcmp(pkg_get_architecture(pkg), arch)) 696 continue; 697 } 698 699 /* check repository */ 700 if (repo) { 701 if (sstrcmp(pkg->src->name, repo)) 702 continue; 703 } 704 705 /* match found */ 706 pkg_found = 1; 707 break; 708 } 709 710 pkg_vec_free(all); 711 712 return pkg_found ? pkg : NULL; 713 } 714 715 /** 716 * @brief Check the accessibility of repositories. 717 * @return return how many repositories cannot access. 0 means all okay. 718 */ 719 int opkg_repository_accessibility_check(void) 720 { 721 pkg_src_list_elt_t *iter; 722 str_list_elt_t *iter1; 723 str_list_t *src; 724 int repositories = 0; 725 int ret = 0; 726 char *repo_ptr; 727 char *stmp; 728 char *host, *end; 729 730 src = str_list_alloc(); 731 732 list_for_each_entry(iter, &conf->pkg_src_list.head, node) { 733 host = strstr(((pkg_src_t *) iter->data)->value, "://") + 3; 734 end = index(host, '/'); 735 if (strstr(((pkg_src_t *) iter->data)->value, "://") && end) 736 stmp = xstrndup(((pkg_src_t *) iter->data)->value, 737 end - 738 ((pkg_src_t *) iter->data)->value); 739 else 740 stmp = xstrdup(((pkg_src_t *) iter->data)->value); 741 742 for (iter1 = str_list_first(src); iter1; 743 iter1 = str_list_next(src, iter1)) { 744 if (strstr(iter1->data, stmp)) 745 break; 746 } 747 if (iter1) 748 continue; 749 750 sprintf_alloc(&repo_ptr, "%s/index.html", stmp); 751 free(stmp); 752 753 str_list_append(src, repo_ptr); 754 free(repo_ptr); 755 repositories++; 756 } 757 758 while (repositories > 0) { 759 iter1 = str_list_pop(src); 760 repositories--; 761 762 if (opkg_download(iter1->data, "/dev/null", 0)) 763 ret++; 764 str_list_elt_deinit(iter1); 765 } 766 767 free(src); 768 769 return ret; 770 } 771
This page was automatically generated by LXR 0.3.1. • OpenWrt