1/* vi: set sw=4 ts=4: */ 2/* 3 * mini dpkg implementation for busybox. 4 * this is not meant as a replacement for dpkg 5 * 6 * written by glenn mcgrath with the help of others 7 * copyright (c) 2001 by glenn mcgrath 8 * 9 * parts of the version comparison code is plucked from the real dpkg 10 * application which is licensed GPLv2 and 11 * copyright (c) 1995 Ian Jackson <ian@chiark.greenend.org.uk> 12 * 13 * started life as a busybox implementation of udpkg 14 * 15 * licensed under gplv2 or later, see file license in this tarball for details. 16 */ 17 18/* 19 * known difference between busybox dpkg and the official dpkg that i don't 20 * consider important, its worth keeping a note of differences anyway, just to 21 * make it easier to maintain. 22 * - the first value for the confflile: field isnt placed on a new line. 23 * - when installing a package the status: field is placed at the end of the 24 * section, rather than just after the package: field. 25 * 26 * bugs that need to be fixed 27 * - (unknown, please let me know when you find any) 28 * 29 */ 30 31#include "libbb.h" 32#include <fnmatch.h> 33#include "unarchive.h" 34 35/* note: if you vary hash_prime sizes be aware, 36 * 1) tweaking these will have a big effect on how much memory this program uses. 37 * 2) for computational efficiency these hash tables should be at least 20% 38 * larger than the maximum number of elements stored in it. 39 * 3) all _hash_prime's must be a prime number or chaos is assured, if your looking 40 * for a prime, try http://www.utm.edu/research/primes/lists/small/10000.txt 41 * 4) if you go bigger than 15 bits you may get into trouble (untested) as its 42 * sometimes cast to an unsigned, if you go to 16 bit you will overlap 43 * int's and chaos is assured, 16381 is the max prime for 14 bit field 44 */ 45 46/* NAME_HASH_PRIME, Stores package names and versions, 47 * I estimate it should be at least 50% bigger than PACKAGE_HASH_PRIME, 48 * as there a lot of duplicate version numbers */ 49#define NAME_HASH_PRIME 16381 50 51/* PACKAGE_HASH_PRIME, Maximum number of unique packages, 52 * It must not be smaller than STATUS_HASH_PRIME, 53 * Currently only packages from status_hashtable are stored in here, but in 54 * future this may be used to store packages not only from a status file, 55 * but an available_hashtable, and even multiple packages files. 56 * Package can be stored more than once if they have different versions. 57 * e.g. The same package may have different versions in the status file 58 * and available file */ 59#define PACKAGE_HASH_PRIME 10007 60typedef struct edge_s { 61 unsigned operator:4; /* was:3 */ 62 unsigned type:4; 63 unsigned name:16; /* was:14 */ 64 unsigned version:16; /* was:14 */ 65} edge_t; 66 67typedef struct common_node_s { 68 unsigned name:16; /* was:14 */ 69 unsigned version:16; /* was:14 */ 70 unsigned num_of_edges:16; /* was:14 */ 71 edge_t **edge; 72} common_node_t; 73 74/* Currently it doesnt store packages that have state-status of not-installed 75 * So it only really has to be the size of the maximum number of packages 76 * likely to be installed at any one time, so there is a bit of leeway here */ 77#define STATUS_HASH_PRIME 8191 78typedef struct status_node_s { 79 unsigned package:16; /* was:14 */ /* has to fit PACKAGE_HASH_PRIME */ 80 unsigned status:16; /* was:14 */ /* has to fit STATUS_HASH_PRIME */ 81} status_node_t; 82 83 84/* Globals */ 85struct globals { 86 char *name_hashtable[NAME_HASH_PRIME + 1]; 87 common_node_t *package_hashtable[PACKAGE_HASH_PRIME + 1]; 88 status_node_t *status_hashtable[STATUS_HASH_PRIME + 1]; 89}; 90#define G (*ptr_to_globals) 91#define name_hashtable (G.name_hashtable ) 92#define package_hashtable (G.package_hashtable) 93#define status_hashtable (G.status_hashtable ) 94#define INIT_G() do { \ 95 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \ 96} while (0) 97 98 99/* Even numbers are for 'extras', like ored dependencies or null */ 100enum edge_type_e { 101 EDGE_NULL = 0, 102 EDGE_PRE_DEPENDS = 1, 103 EDGE_OR_PRE_DEPENDS = 2, 104 EDGE_DEPENDS = 3, 105 EDGE_OR_DEPENDS = 4, 106 EDGE_REPLACES = 5, 107 EDGE_PROVIDES = 7, 108 EDGE_CONFLICTS = 9, 109 EDGE_SUGGESTS = 11, 110 EDGE_RECOMMENDS = 13, 111 EDGE_ENHANCES = 15 112}; 113enum operator_e { 114 VER_NULL = 0, 115 VER_EQUAL = 1, 116 VER_LESS = 2, 117 VER_LESS_EQUAL = 3, 118 VER_MORE = 4, 119 VER_MORE_EQUAL = 5, 120 VER_ANY = 6 121}; 122 123typedef struct deb_file_s { 124 char *control_file; 125 char *filename; 126 unsigned package:16; /* was:14 */ 127} deb_file_t; 128 129 130static void make_hash(const char *key, unsigned *start, unsigned *decrement, const int hash_prime) 131{ 132 unsigned long hash_num = key[0]; 133 int len = strlen(key); 134 int i; 135 136 /* Maybe i should have uses a "proper" hashing algorithm here instead 137 * of making one up myself, seems to be working ok though. */ 138 for (i = 1; i < len; i++) { 139 /* shifts the ascii based value and adds it to previous value 140 * shift amount is mod 24 because long int is 32 bit and data 141 * to be shifted is 8, don't want to shift data to where it has 142 * no effect */ 143 hash_num += (key[i] + key[i-1]) << ((key[i] * i) % 24); 144 } 145 *start = (unsigned) hash_num % hash_prime; 146 *decrement = (unsigned) 1 + (hash_num % (hash_prime - 1)); 147} 148 149/* this adds the key to the hash table */ 150static int search_name_hashtable(const char *key) 151{ 152 unsigned probe_address; 153 unsigned probe_decrement; 154 155 make_hash(key, &probe_address, &probe_decrement, NAME_HASH_PRIME); 156 while (name_hashtable[probe_address] != NULL) { 157 if (strcmp(name_hashtable[probe_address], key) == 0) { 158 return probe_address; 159 } 160 probe_address -= probe_decrement; 161 if ((int)probe_address < 0) { 162 probe_address += NAME_HASH_PRIME; 163 } 164 } 165 name_hashtable[probe_address] = xstrdup(key); 166 return probe_address; 167} 168 169/* this DOESNT add the key to the hashtable 170 * TODO make it consistent with search_name_hashtable 171 */ 172static unsigned search_status_hashtable(const char *key) 173{ 174 unsigned probe_address; 175 unsigned probe_decrement; 176 177 make_hash(key, &probe_address, &probe_decrement, STATUS_HASH_PRIME); 178 while (status_hashtable[probe_address] != NULL) { 179 if (strcmp(key, name_hashtable[package_hashtable[status_hashtable[probe_address]->package]->name]) == 0) { 180 break; 181 } 182 probe_address -= probe_decrement; 183 if ((int)probe_address < 0) { 184 probe_address += STATUS_HASH_PRIME; 185 } 186 } 187 return probe_address; 188} 189 190static int order(char x) 191{ 192 return (x == '~' ? -1 193 : x == '\0' ? 0 194 : isdigit(x) ? 0 195 : isalpha(x) ? x 196 : (unsigned char)x + 256 197 ); 198} 199 200/* This code is taken from dpkg and modified slightly to work with busybox */ 201static int version_compare_part(const char *val, const char *ref) 202{ 203 if (!val) val = ""; 204 if (!ref) ref = ""; 205 206 while (*val || *ref) { 207 int first_diff; 208 209 while ((*val && !isdigit(*val)) || (*ref && !isdigit(*ref))) { 210 int vc = order(*val); 211 int rc = order(*ref); 212 if (vc != rc) 213 return vc - rc; 214 val++; 215 ref++; 216 } 217 218 while (*val == '0') 219 val++; 220 while (*ref == '0') 221 ref++; 222 223 first_diff = 0; 224 while (isdigit(*val) && isdigit(*ref)) { 225 if (first_diff == 0) 226 first_diff = *val - *ref; 227 val++; 228 ref++; 229 } 230 if (isdigit(*val)) 231 return 1; 232 if (isdigit(*ref)) 233 return -1; 234 if (first_diff) 235 return first_diff; 236 } 237 return 0; 238} 239 240/* if ver1 < ver2 return -1, 241 * if ver1 = ver2 return 0, 242 * if ver1 > ver2 return 1, 243 */ 244static int version_compare(const unsigned ver1, const unsigned ver2) 245{ 246 char *ch_ver1 = name_hashtable[ver1]; 247 char *ch_ver2 = name_hashtable[ver2]; 248 unsigned epoch1 = 0, epoch2 = 0; 249 char *colon; 250 char *deb_ver1, *deb_ver2; 251 char *upstream_ver1; 252 char *upstream_ver2; 253 int result; 254 255 /* Compare epoch */ 256 colon = strchr(ch_ver1, ':'); 257 if (colon) { 258 epoch1 = atoi(ch_ver1); 259 ch_ver1 = colon + 1; 260 } 261 colon = strchr(ch_ver2, ':'); 262 if (colon) { 263 epoch2 = atoi(ch_ver2); 264 ch_ver2 = colon + 1; 265 } 266 if (epoch1 < epoch2) { 267 return -1; 268 } 269 if (epoch1 > epoch2) { 270 return 1; 271 } 272 273 /* Compare upstream version */ 274 upstream_ver1 = xstrdup(ch_ver1); 275 upstream_ver2 = xstrdup(ch_ver2); 276 277 /* Chop off debian version, and store for later use */ 278 deb_ver1 = strrchr(upstream_ver1, '-'); 279 deb_ver2 = strrchr(upstream_ver2, '-'); 280 if (deb_ver1) { 281 *deb_ver1++ = '\0'; 282 } 283 if (deb_ver2) { 284 *deb_ver2++ = '\0'; 285 } 286 result = version_compare_part(upstream_ver1, upstream_ver2); 287 if (result == 0) { 288 /* Compare debian versions */ 289 result = version_compare_part(deb_ver1, deb_ver2); 290 } 291 292 free(upstream_ver1); 293 free(upstream_ver2); 294 return result; 295} 296 297static int test_version(const unsigned version1, const unsigned version2, const unsigned operator) 298{ 299 const int version_result = version_compare(version1, version2); 300 switch (operator) { 301 case VER_ANY: 302 return TRUE; 303 case VER_EQUAL: 304 return (version_result == 0); 305 case VER_LESS: 306 return (version_result < 0); 307 case VER_LESS_EQUAL: 308 return (version_result <= 0); 309 case VER_MORE: 310 return (version_result > 0); 311 case VER_MORE_EQUAL: 312 return (version_result >= 0); 313 } 314 return FALSE; 315} 316 317static int search_package_hashtable(const unsigned name, const unsigned version, const unsigned operator) 318{ 319 unsigned probe_address; 320 unsigned probe_decrement; 321 322 make_hash(name_hashtable[name], &probe_address, &probe_decrement, PACKAGE_HASH_PRIME); 323 while (package_hashtable[probe_address] != NULL) { 324 if (package_hashtable[probe_address]->name == name) { 325 if (operator == VER_ANY) { 326 return probe_address; 327 } 328 if (test_version(package_hashtable[probe_address]->version, version, operator)) { 329 return probe_address; 330 } 331 } 332 probe_address -= probe_decrement; 333 if ((int)probe_address < 0) { 334 probe_address += PACKAGE_HASH_PRIME; 335 } 336 } 337 return probe_address; 338} 339 340/* 341 * This function searches through the entire package_hashtable looking 342 * for a package which provides "needle". It returns the index into 343 * the package_hashtable for the providing package. 344 * 345 * needle is the index into name_hashtable of the package we are 346 * looking for. 347 * 348 * start_at is the index in the package_hashtable to start looking 349 * at. If start_at is -1 then start at the beginning. This is to allow 350 * for repeated searches since more than one package might provide 351 * needle. 352 * 353 * FIXME: I don't think this is very efficient, but I thought I'd keep 354 * it simple for now until it proves to be a problem. 355 */ 356static int search_for_provides(int needle, int start_at) 357{ 358 int i, j; 359 common_node_t *p; 360 for (i = start_at + 1; i < PACKAGE_HASH_PRIME; i++) { 361 p = package_hashtable[i]; 362 if (p == NULL) 363 continue; 364 for (j = 0; j < p->num_of_edges; j++) 365 if (p->edge[j]->type == EDGE_PROVIDES && p->edge[j]->name == needle) 366 return i; 367 } 368 return -1; 369} 370 371/* 372 * Add an edge to a node 373 */ 374static void add_edge_to_node(common_node_t *node, edge_t *edge) 375{ 376 node->edge = xrealloc_vector(node->edge, 2, node->num_of_edges); 377 node->edge[node->num_of_edges++] = edge; 378} 379 380/* 381 * Create one new node and one new edge for every dependency. 382 * 383 * Dependencies which contain multiple alternatives are represented as 384 * an EDGE_OR_PRE_DEPENDS or EDGE_OR_DEPENDS node, followed by a 385 * number of EDGE_PRE_DEPENDS or EDGE_DEPENDS nodes. The name field of 386 * the OR edge contains the full dependency string while the version 387 * field contains the number of EDGE nodes which follow as part of 388 * this alternative. 389 */ 390static void add_split_dependencies(common_node_t *parent_node, const char *whole_line, unsigned edge_type) 391{ 392 char *line = xstrdup(whole_line); 393 char *line2; 394 char *line_ptr1 = NULL; 395 char *line_ptr2 = NULL; 396 char *field; 397 char *field2; 398 char *version; 399 edge_t *edge; 400 edge_t *or_edge; 401 int offset_ch; 402 403 field = strtok_r(line, ",", &line_ptr1); 404 do { 405 /* skip leading spaces */ 406 field += strspn(field, " "); 407 line2 = xstrdup(field); 408 field2 = strtok_r(line2, "|", &line_ptr2); 409 or_edge = NULL; 410 if ((edge_type == EDGE_DEPENDS || edge_type == EDGE_PRE_DEPENDS) 411 && (strcmp(field, field2) != 0) 412 ) { 413 or_edge = xzalloc(sizeof(edge_t)); 414 or_edge->type = edge_type + 1; 415 or_edge->name = search_name_hashtable(field); 416 //or_edge->version = 0; // tracks the number of alternatives 417 add_edge_to_node(parent_node, or_edge); 418 } 419 420 do { 421 edge = xmalloc(sizeof(edge_t)); 422 edge->type = edge_type; 423 424 /* Skip any extra leading spaces */ 425 field2 += strspn(field2, " "); 426 427 /* Get dependency version info */ 428 version = strchr(field2, '('); 429 if (version == NULL) { 430 edge->operator = VER_ANY; 431 /* Get the versions hash number, adding it if the number isnt already in there */ 432 edge->version = search_name_hashtable("ANY"); 433 } else { 434 /* Skip leading ' ' or '(' */ 435 version += strspn(version, " ("); 436 /* Calculate length of any operator characters */ 437 offset_ch = strspn(version, "<=>"); 438 /* Determine operator */ 439 if (offset_ch > 0) { 440 if (strncmp(version, "=", offset_ch) == 0) { 441 edge->operator = VER_EQUAL; 442 } else if (strncmp(version, "<<", offset_ch) == 0) { 443 edge->operator = VER_LESS; 444 } else if (strncmp(version, "<=", offset_ch) == 0) { 445 edge->operator = VER_LESS_EQUAL; 446 } else if (strncmp(version, ">>", offset_ch) == 0) { 447 edge->operator = VER_MORE; 448 } else if (strncmp(version, ">=", offset_ch) == 0) { 449 edge->operator = VER_MORE_EQUAL; 450 } else { 451 bb_error_msg_and_die("illegal operator"); 452 } 453 } 454 /* skip to start of version numbers */ 455 version += offset_ch; 456 version += strspn(version, " "); 457 458 /* Truncate version at trailing ' ' or ')' */ 459 version[strcspn(version, " )")] = '\0'; 460 /* Get the versions hash number, adding it if the number isnt already in there */ 461 edge->version = search_name_hashtable(version); 462 } 463 464 /* Get the dependency name */ 465 field2[strcspn(field2, " (")] = '\0'; 466 edge->name = search_name_hashtable(field2); 467 468 if (or_edge) 469 or_edge->version++; 470 471 add_edge_to_node(parent_node, edge); 472 field2 = strtok_r(NULL, "|", &line_ptr2); 473 } while (field2 != NULL); 474 475 free(line2); 476 field = strtok_r(NULL, ",", &line_ptr1); 477 } while (field != NULL); 478 479 free(line); 480} 481 482static void free_package(common_node_t *node) 483{ 484 unsigned i; 485 if (node) { 486 for (i = 0; i < node->num_of_edges; i++) { 487 free(node->edge[i]); 488 } 489 free(node->edge); 490 free(node); 491 } 492} 493 494/* 495 * Gets the next package field from package_buffer, separated into the field name 496 * and field value, it returns the int offset to the first character of the next field 497 */ 498static int read_package_field(const char *package_buffer, char **field_name, char **field_value) 499{ 500 int offset_name_start = 0; 501 int offset_name_end = 0; 502 int offset_value_start = 0; 503 int offset_value_end = 0; 504 int offset = 0; 505 int next_offset; 506 int name_length; 507 int value_length; 508 int exit_flag = FALSE; 509 510 if (package_buffer == NULL) { 511 *field_name = NULL; 512 *field_value = NULL; 513 return -1; 514 } 515 while (1) { 516 next_offset = offset + 1; 517 switch (package_buffer[offset]) { 518 case '\0': 519 exit_flag = TRUE; 520 break; 521 case ':': 522 if (offset_name_end == 0) { 523 offset_name_end = offset; 524 offset_value_start = next_offset; 525 } 526 /* TODO: Name might still have trailing spaces if ':' isnt 527 * immediately after name */ 528 break; 529 case '\n': 530 /* TODO: The char next_offset may be out of bounds */ 531 if (package_buffer[next_offset] != ' ') { 532 exit_flag = TRUE; 533 break; 534 } 535 case '\t': 536 case ' ': 537 /* increment the value start point if its a just filler */ 538 if (offset_name_start == offset) { 539 offset_name_start++; 540 } 541 if (offset_value_start == offset) { 542 offset_value_start++; 543 } 544 break; 545 } 546 if (exit_flag) { 547 /* Check that the names are valid */ 548 offset_value_end = offset; 549 name_length = offset_name_end - offset_name_start; 550 value_length = offset_value_end - offset_value_start; 551 if (name_length == 0) { 552 break; 553 } 554 if ((name_length > 0) && (value_length > 0)) { 555 break; 556 } 557 558 /* If not valid, start fresh with next field */ 559 exit_flag = FALSE; 560 offset_name_start = offset + 1; 561 offset_name_end = 0; 562 offset_value_start = offset + 1; 563 offset_value_end = offset + 1; 564 offset++; 565 } 566 offset++; 567 } 568 *field_name = NULL; 569 if (name_length) { 570 *field_name = xstrndup(&package_buffer[offset_name_start], name_length); 571 } 572 *field_value = NULL; 573 if (value_length > 0) { 574 *field_value = xstrndup(&package_buffer[offset_value_start], value_length); 575 } 576 return next_offset; 577} 578 579static unsigned fill_package_struct(char *control_buffer) 580{ 581 static const char field_names[] ALIGN1 = 582 "Package\0""Version\0" 583 "Pre-Depends\0""Depends\0""Replaces\0""Provides\0" 584 "Conflicts\0""Suggests\0""Recommends\0""Enhances\0"; 585 586 common_node_t *new_node = xzalloc(sizeof(common_node_t)); 587 char *field_name; 588 char *field_value; 589 int field_start = 0; 590 int num = -1; 591 int buffer_length = strlen(control_buffer); 592 593 new_node->version = search_name_hashtable("unknown"); 594 while (field_start < buffer_length) { 595 unsigned field_num; 596 597 field_start += read_package_field(&control_buffer[field_start], 598 &field_name, &field_value); 599 600 if (field_name == NULL) { 601 goto fill_package_struct_cleanup; 602 } 603 604 field_num = index_in_strings(field_names, field_name); 605 switch (field_num) { 606 case 0: /* Package */ 607 new_node->name = search_name_hashtable(field_value); 608 break; 609 case 1: /* Version */ 610 new_node->version = search_name_hashtable(field_value); 611 break; 612 case 2: /* Pre-Depends */ 613 add_split_dependencies(new_node, field_value, EDGE_PRE_DEPENDS); 614 break; 615 case 3: /* Depends */ 616 add_split_dependencies(new_node, field_value, EDGE_DEPENDS); 617 break; 618 case 4: /* Replaces */ 619 add_split_dependencies(new_node, field_value, EDGE_REPLACES); 620 break; 621 case 5: /* Provides */ 622 add_split_dependencies(new_node, field_value, EDGE_PROVIDES); 623 break; 624 case 6: /* Conflicts */ 625 add_split_dependencies(new_node, field_value, EDGE_CONFLICTS); 626 break; 627 case 7: /* Suggests */ 628 add_split_dependencies(new_node, field_value, EDGE_SUGGESTS); 629 break; 630 case 8: /* Recommends */ 631 add_split_dependencies(new_node, field_value, EDGE_RECOMMENDS); 632 break; 633 case 9: /* Enhances */ 634 add_split_dependencies(new_node, field_value, EDGE_ENHANCES); 635 break; 636 } 637 fill_package_struct_cleanup: 638 free(field_name); 639 free(field_value); 640 } 641 642 if (new_node->version == search_name_hashtable("unknown")) { 643 free_package(new_node); 644 return -1; 645 } 646 num = search_package_hashtable(new_node->name, new_node->version, VER_EQUAL); 647 free_package(package_hashtable[num]); 648 package_hashtable[num] = new_node; 649 return num; 650} 651 652/* if num = 1, it returns the want status, 2 returns flag, 3 returns status */ 653static unsigned get_status(const unsigned status_node, const int num) 654{ 655 char *status_string = name_hashtable[status_hashtable[status_node]->status]; 656 char *state_sub_string; 657 unsigned state_sub_num; 658 int len; 659 int i; 660 661 /* set tmp_string to point to the start of the word number */ 662 for (i = 1; i < num; i++) { 663 /* skip past a word */ 664 status_string += strcspn(status_string, " "); 665 /* skip past the separating spaces */ 666 status_string += strspn(status_string, " "); 667 } 668 len = strcspn(status_string, " \n"); 669 state_sub_string = xstrndup(status_string, len); 670 state_sub_num = search_name_hashtable(state_sub_string); 671 free(state_sub_string); 672 return state_sub_num; 673} 674 675static void set_status(const unsigned status_node_num, const char *new_value, const int position) 676{ 677 const unsigned new_value_len = strlen(new_value); 678 const unsigned new_value_num = search_name_hashtable(new_value); 679 unsigned want = get_status(status_node_num, 1); 680 unsigned flag = get_status(status_node_num, 2); 681 unsigned status = get_status(status_node_num, 3); 682 int want_len = strlen(name_hashtable[want]); 683 int flag_len = strlen(name_hashtable[flag]); 684 int status_len = strlen(name_hashtable[status]); 685 char *new_status; 686 687 switch (position) { 688 case 1: 689 want = new_value_num; 690 want_len = new_value_len; 691 break; 692 case 2: 693 flag = new_value_num; 694 flag_len = new_value_len; 695 break; 696 case 3: 697 status = new_value_num; 698 status_len = new_value_len; 699 break; 700 default: 701 bb_error_msg_and_die("DEBUG ONLY: this shouldnt happen"); 702 } 703 704 new_status = xasprintf("%s %s %s", name_hashtable[want], name_hashtable[flag], name_hashtable[status]); 705 status_hashtable[status_node_num]->status = search_name_hashtable(new_status); 706 free(new_status); 707} 708 709static const char *describe_status(int status_num) 710{ 711 int status_want, status_state; 712 if (status_hashtable[status_num] == NULL || status_hashtable[status_num]->status == 0) 713 return "is not installed or flagged to be installed"; 714 715 status_want = get_status(status_num, 1); 716 status_state = get_status(status_num, 3); 717 718 if (status_state == search_name_hashtable("installed")) { 719 if (status_want == search_name_hashtable("install")) 720 return "is installed"; 721 if (status_want == search_name_hashtable("deinstall")) 722 return "is marked to be removed"; 723 if (status_want == search_name_hashtable("purge")) 724 return "is marked to be purged"; 725 } 726 if (status_want == search_name_hashtable("unknown")) 727 return "is in an indeterminate state"; 728 if (status_want == search_name_hashtable("install")) 729 return "is marked to be installed"; 730 731 return "is not installed or flagged to be installed"; 732} 733 734static void index_status_file(const char *filename) 735{ 736 FILE *status_file; 737 char *control_buffer; 738 char *status_line; 739 status_node_t *status_node = NULL; 740 unsigned status_num; 741 742 status_file = xfopen_for_read(filename); 743 while ((control_buffer = xmalloc_fgetline_str(status_file, "\n\n")) != NULL) { 744 const unsigned package_num = fill_package_struct(control_buffer); 745 if (package_num != -1) { 746 status_node = xmalloc(sizeof(status_node_t)); 747 /* fill_package_struct doesnt handle the status field */ 748 status_line = strstr(control_buffer, "Status:"); 749 if (status_line != NULL) { 750 status_line += 7; 751 status_line += strspn(status_line, " \n\t"); 752 status_line = xstrndup(status_line, strcspn(status_line, "\n")); 753 status_node->status = search_name_hashtable(status_line); 754 free(status_line); 755 } 756 status_node->package = package_num; 757 status_num = search_status_hashtable(name_hashtable[package_hashtable[status_node->package]->name]); 758 status_hashtable[status_num] = status_node; 759 } 760 free(control_buffer); 761 } 762 fclose(status_file); 763} 764 765static void write_buffer_no_status(FILE *new_status_file, const char *control_buffer) 766{ 767 char *name; 768 char *value; 769 int start = 0; 770 while (1) { 771 start += read_package_field(&control_buffer[start], &name, &value); 772 if (name == NULL) { 773 break; 774 } 775 if (strcmp(name, "Status") != 0) { 776 fprintf(new_status_file, "%s: %s\n", name, value); 777 } 778 } 779} 780 781/* This could do with a cleanup */ 782static void write_status_file(deb_file_t **deb_file) 783{ 784 FILE *old_status_file = xfopen_for_read("/var/lib/dpkg/status"); 785 FILE *new_status_file = xfopen_for_write("/var/lib/dpkg/status.udeb"); 786 char *package_name; 787 char *status_from_file; 788 char *control_buffer = NULL; 789 char *tmp_string; 790 int status_num; 791 int field_start = 0; 792 int write_flag; 793 int i = 0; 794 795 /* Update previously known packages */ 796 while ((control_buffer = xmalloc_fgetline_str(old_status_file, "\n\n")) != NULL) { 797 tmp_string = strstr(control_buffer, "Package:"); 798 if (tmp_string == NULL) { 799 continue; 800 } 801 802 tmp_string += 8; 803 tmp_string += strspn(tmp_string, " \n\t"); 804 package_name = xstrndup(tmp_string, strcspn(tmp_string, "\n")); 805 write_flag = FALSE; 806 tmp_string = strstr(control_buffer, "Status:"); 807 if (tmp_string != NULL) { 808 /* Separate the status value from the control buffer */ 809 tmp_string += 7; 810 tmp_string += strspn(tmp_string, " \n\t"); 811 status_from_file = xstrndup(tmp_string, strcspn(tmp_string, "\n")); 812 } else { 813 status_from_file = NULL; 814 } 815 816 /* Find this package in the status hashtable */ 817 status_num = search_status_hashtable(package_name); 818 if (status_hashtable[status_num] != NULL) { 819 const char *status_from_hashtable = name_hashtable[status_hashtable[status_num]->status]; 820 if (strcmp(status_from_file, status_from_hashtable) != 0) { 821 /* New status isnt exactly the same as old status */ 822 const int state_status = get_status(status_num, 3); 823 if ((strcmp("installed", name_hashtable[state_status]) == 0) 824 || (strcmp("unpacked", name_hashtable[state_status]) == 0) 825 ) { 826 /* We need to add the control file from the package */ 827 i = 0; 828 while (deb_file[i] != NULL) { 829 if (strcmp(package_name, name_hashtable[package_hashtable[deb_file[i]->package]->name]) == 0) { 830 /* Write a status file entry with a modified status */ 831 /* remove trailing \n's */ 832 write_buffer_no_status(new_status_file, deb_file[i]->control_file); 833 set_status(status_num, "ok", 2); 834 fprintf(new_status_file, "Status: %s\n\n", 835 name_hashtable[status_hashtable[status_num]->status]); 836 write_flag = TRUE; 837 break; 838 } 839 i++; 840 } 841 /* This is temperary, debugging only */ 842 if (deb_file[i] == NULL) { 843 bb_error_msg_and_die("ALERT: cannot find a control file, " 844 "your status file may be broken, status may be " 845 "incorrect for %s", package_name); 846 } 847 } 848 else if (strcmp("not-installed", name_hashtable[state_status]) == 0) { 849 /* Only write the Package, Status, Priority and Section lines */ 850 fprintf(new_status_file, "Package: %s\n", package_name); 851 fprintf(new_status_file, "Status: %s\n", status_from_hashtable); 852 853 while (1) { 854 char *field_name; 855 char *field_value; 856 field_start += read_package_field(&control_buffer[field_start], &field_name, &field_value); 857 if (field_name == NULL) { 858 break; 859 } 860 if ((strcmp(field_name, "Priority") == 0) 861 || (strcmp(field_name, "Section") == 0) 862 ) { 863 fprintf(new_status_file, "%s: %s\n", field_name, field_value); 864 } 865 } 866 write_flag = TRUE; 867 fputs("\n", new_status_file); 868 } 869 else if (strcmp("config-files", name_hashtable[state_status]) == 0) { 870 /* only change the status line */ 871 while (1) { 872 char *field_name; 873 char *field_value; 874 field_start += read_package_field(&control_buffer[field_start], &field_name, &field_value); 875 if (field_name == NULL) { 876 break; 877 } 878 /* Setup start point for next field */ 879 if (strcmp(field_name, "Status") == 0) { 880 fprintf(new_status_file, "Status: %s\n", status_from_hashtable); 881 } else { 882 fprintf(new_status_file, "%s: %s\n", field_name, field_value); 883 } 884 } 885 write_flag = TRUE; 886 fputs("\n", new_status_file); 887 } 888 } 889 } 890 /* If the package from the status file wasnt handle above, do it now*/ 891 if (!write_flag) { 892 fprintf(new_status_file, "%s\n\n", control_buffer); 893 } 894 895 free(status_from_file); 896 free(package_name); 897 free(control_buffer); 898 } 899 900 /* Write any new packages */ 901 for (i = 0; deb_file[i] != NULL; i++) { 902 status_num = search_status_hashtable(name_hashtable[package_hashtable[deb_file[i]->package]->name]); 903 if (strcmp("reinstreq", name_hashtable[get_status(status_num, 2)]) == 0) { 904 write_buffer_no_status(new_status_file, deb_file[i]->control_file); 905 set_status(status_num, "ok", 2); 906 fprintf(new_status_file, "Status: %s\n\n", name_hashtable[status_hashtable[status_num]->status]); 907 } 908 } 909 fclose(old_status_file); 910 fclose(new_status_file); 911 912 /* Create a separate backfile to dpkg */ 913 if (rename("/var/lib/dpkg/status", "/var/lib/dpkg/status.udeb.bak") == -1) { 914 if (errno != ENOENT) 915 bb_error_msg_and_die("can't create backup status file"); 916 /* Its ok if renaming the status file fails because status 917 * file doesnt exist, maybe we are starting from scratch */ 918 bb_error_msg("no status file found, creating new one"); 919 } 920 921 xrename("/var/lib/dpkg/status.udeb", "/var/lib/dpkg/status"); 922} 923 924/* This function returns TRUE if the given package can satisfy a 925 * dependency of type depend_type. 926 * 927 * A pre-depends is satisfied only if a package is already installed, 928 * which a regular depends can be satisfied by a package which we want 929 * to install. 930 */ 931static int package_satisfies_dependency(int package, int depend_type) 932{ 933 int status_num = search_status_hashtable(name_hashtable[package_hashtable[package]->name]); 934 935 /* status could be unknown if package is a pure virtual 936 * provides which cannot satisfy any dependency by itself. 937 */ 938 if (status_hashtable[status_num] == NULL) 939 return 0; 940 941 switch (depend_type) { 942 case EDGE_PRE_DEPENDS: return get_status(status_num, 3) == search_name_hashtable("installed"); 943 case EDGE_DEPENDS: return get_status(status_num, 1) == search_name_hashtable("install"); 944 } 945 return 0; 946} 947 948static int check_deps(deb_file_t **deb_file, int deb_start /*, int dep_max_count - ?? */) 949{ 950 int *conflicts = NULL; 951 int conflicts_num = 0; 952 int i = deb_start; 953 int j; 954 955 /* Check for conflicts 956 * TODO: TEST if conflicts with other packages to be installed 957 * 958 * Add install packages and the packages they provide 959 * to the list of files to check conflicts for 960 */ 961 962 /* Create array of package numbers to check against 963 * installed package for conflicts*/ 964 while (deb_file[i] != NULL) { 965 const unsigned package_num = deb_file[i]->package; 966 conflicts = xrealloc_vector(conflicts, 2, conflicts_num); 967 conflicts[conflicts_num] = package_num; 968 conflicts_num++; 969 /* add provides to conflicts list */ 970 for (j = 0; j < package_hashtable[package_num]->num_of_edges; j++) { 971 if (package_hashtable[package_num]->edge[j]->type == EDGE_PROVIDES) { 972 const int conflicts_package_num = search_package_hashtable( 973 package_hashtable[package_num]->edge[j]->name, 974 package_hashtable[package_num]->edge[j]->version, 975 package_hashtable[package_num]->edge[j]->operator); 976 if (package_hashtable[conflicts_package_num] == NULL) { 977 /* create a new package */ 978 common_node_t *new_node = xzalloc(sizeof(common_node_t)); 979 new_node->name = package_hashtable[package_num]->edge[j]->name; 980 new_node->version = package_hashtable[package_num]->edge[j]->version; 981 package_hashtable[conflicts_package_num] = new_node; 982 } 983 conflicts = xrealloc_vector(conflicts, 2, conflicts_num); 984 conflicts[conflicts_num] = conflicts_package_num; 985 conflicts_num++; 986 } 987 } 988 i++; 989 } 990 991 /* Check conflicts */ 992 i = 0; 993 while (deb_file[i] != NULL) { 994 const common_node_t *package_node = package_hashtable[deb_file[i]->package]; 995 int status_num = 0; 996 status_num = search_status_hashtable(name_hashtable[package_node->name]); 997 998 if (get_status(status_num, 3) == search_name_hashtable("installed")) { 999 i++; 1000 continue; 1001 } 1002 1003 for (j = 0; j < package_node->num_of_edges; j++) { 1004 const edge_t *package_edge = package_node->edge[j]; 1005 1006 if (package_edge->type == EDGE_CONFLICTS) { 1007 const unsigned package_num = 1008 search_package_hashtable(package_edge->name, 1009 package_edge->version, 1010 package_edge->operator); 1011 int result = 0; 1012 if (package_hashtable[package_num] != NULL) { 1013 status_num = search_status_hashtable(name_hashtable[package_hashtable[package_num]->name]); 1014 1015 if (get_status(status_num, 1) == search_name_hashtable("install")) { 1016 result = test_version(package_hashtable[deb_file[i]->package]->version, 1017 package_edge->version, package_edge->operator); 1018 } 1019 } 1020 1021 if (result) { 1022 bb_error_msg_and_die("package %s conflicts with %s", 1023 name_hashtable[package_node->name], 1024 name_hashtable[package_edge->name]); 1025 } 1026 } 1027 } 1028 i++; 1029 } 1030 1031 1032 /* Check dependendcies */ 1033 for (i = 0; i < PACKAGE_HASH_PRIME; i++) { 1034 int status_num = 0; 1035 int number_of_alternatives = 0; 1036 const edge_t * root_of_alternatives = NULL; 1037 const common_node_t *package_node = package_hashtable[i]; 1038 1039 /* If the package node does not exist then this 1040 * package is a virtual one. In which case there are 1041 * no dependencies to check. 1042 */ 1043 if (package_node == NULL) continue; 1044 1045 status_num = search_status_hashtable(name_hashtable[package_node->name]); 1046 1047 /* If there is no status then this package is a 1048 * virtual one provided by something else. In which 1049 * case there are no dependencies to check. 1050 */ 1051 if (status_hashtable[status_num] == NULL) continue; 1052 1053 /* If we don't want this package installed then we may 1054 * as well ignore it's dependencies. 1055 */ 1056 if (get_status(status_num, 1) != search_name_hashtable("install")) { 1057 continue; 1058 } 1059 1060 /* This code is tested only for EDGE_DEPENDS, since I 1061 * have no suitable pre-depends available. There is no 1062 * reason that it shouldn't work though :-) 1063 */ 1064 for (j = 0; j < package_node->num_of_edges; j++) { 1065 const edge_t *package_edge = package_node->edge[j]; 1066 unsigned package_num; 1067 1068 if (package_edge->type == EDGE_OR_PRE_DEPENDS 1069 || package_edge->type == EDGE_OR_DEPENDS 1070 ) { /* start an EDGE_OR_ list */ 1071 number_of_alternatives = package_edge->version; 1072 root_of_alternatives = package_edge; 1073 continue; 1074 } 1075 if (number_of_alternatives == 0) { /* not in the middle of an EDGE_OR_ list */ 1076 number_of_alternatives = 1; 1077 root_of_alternatives = NULL; 1078 } 1079 1080 package_num = search_package_hashtable(package_edge->name, package_edge->version, package_edge->operator); 1081 1082 if (package_edge->type == EDGE_PRE_DEPENDS 1083 || package_edge->type == EDGE_DEPENDS 1084 ) { 1085 int result=1; 1086 status_num = 0; 1087 1088 /* If we are inside an alternative then check 1089 * this edge is the right type. 1090 * 1091 * EDGE_DEPENDS == OR_DEPENDS -1 1092 * EDGE_PRE_DEPENDS == OR_PRE_DEPENDS -1 1093 */ 1094 if (root_of_alternatives && package_edge->type != root_of_alternatives->type - 1) 1095 bb_error_msg_and_die("fatal error, package dependencies corrupt: %d != %d - 1", 1096 package_edge->type, root_of_alternatives->type); 1097 1098 if (package_hashtable[package_num] != NULL) 1099 result = !package_satisfies_dependency(package_num, package_edge->type); 1100 1101 if (result) { /* check for other package which provide what we are looking for */ 1102 int provider = -1; 1103 1104 while ((provider = search_for_provides(package_edge->name, provider)) > -1) { 1105 if (package_hashtable[provider] == NULL) { 1106 puts("Have a provider but no package information for it"); 1107 continue; 1108 } 1109 result = !package_satisfies_dependency(provider, package_edge->type); 1110 1111 if (result == 0) 1112 break; 1113 } 1114 } 1115 1116 /* It must be already installed, or to be installed */ 1117 number_of_alternatives--; 1118 if (result && number_of_alternatives == 0) { 1119 if (root_of_alternatives) 1120 bb_error_msg_and_die( 1121 "package %s %sdepends on %s, " 1122 "which cannot be satisfied", 1123 name_hashtable[package_node->name], 1124 package_edge->type == EDGE_PRE_DEPENDS ? "pre-" : "", 1125 name_hashtable[root_of_alternatives->name]); 1126 bb_error_msg_and_die( 1127 "package %s %sdepends on %s, which %s\n", 1128 name_hashtable[package_node->name], 1129 package_edge->type == EDGE_PRE_DEPENDS ? "pre-" : "", 1130 name_hashtable[package_edge->name], 1131 describe_status(status_num)); 1132 } 1133 if (result == 0 && number_of_alternatives) { 1134 /* we've found a package which 1135 * satisfies the dependency, 1136 * so skip over the rest of 1137 * the alternatives. 1138 */ 1139 j += number_of_alternatives; 1140 number_of_alternatives = 0; 1141 } 1142 } 1143 } 1144 } 1145 free(conflicts); 1146 return TRUE; 1147} 1148 1149static char **create_list(const char *filename) 1150{ 1151 FILE *list_stream; 1152 char **file_list; 1153 char *line; 1154 int count; 1155 1156 /* don't use [xw]fopen here, handle error ourself */ 1157 list_stream = fopen_for_read(filename); 1158 if (list_stream == NULL) { 1159 return NULL; 1160 } 1161 1162 file_list = NULL; 1163 count = 0; 1164 while ((line = xmalloc_fgetline(list_stream)) != NULL) { 1165 file_list = xrealloc_vector(file_list, 2, count); 1166 file_list[count++] = line; 1167 /*file_list[count] = NULL; - xrealloc_vector did it */ 1168 } 1169 fclose(list_stream); 1170 1171 return file_list; 1172} 1173 1174/* maybe i should try and hook this into remove_file.c somehow */ 1175static int remove_file_array(char **remove_names, char **exclude_names) 1176{ 1177 struct stat path_stat; 1178 int remove_flag = 1; /* not removed anything yet */ 1179 int i, j; 1180 1181 if (remove_names == NULL) { 1182 return 0; 1183 } 1184 for (i = 0; remove_names[i] != NULL; i++) { 1185 if (exclude_names != NULL) { 1186 for (j = 0; exclude_names[j] != NULL; j++) { 1187 if (strcmp(remove_names[i], exclude_names[j]) == 0) { 1188 goto skip; 1189 } 1190 } 1191 } 1192 /* TODO: why we are checking lstat? we can just try rm/rmdir */ 1193 if (lstat(remove_names[i], &path_stat) < 0) { 1194 continue; 1195 } 1196 if (S_ISDIR(path_stat.st_mode)) { 1197 remove_flag &= rmdir(remove_names[i]); /* 0 if no error */ 1198 } else { 1199 remove_flag &= unlink(remove_names[i]); /* 0 if no error */ 1200 } 1201 skip: 1202 continue; 1203 } 1204 return (remove_flag == 0); 1205} 1206 1207static void run_package_script_or_die(const char *package_name, const char *script_type) 1208{ 1209 char *script_path; 1210 int result; 1211 1212 script_path = xasprintf("/var/lib/dpkg/info/%s.%s", package_name, script_type); 1213 1214 /* If the file doesnt exist is isnt fatal */ 1215 result = access(script_path, F_OK) ? EXIT_SUCCESS : system(script_path); 1216 free(script_path); 1217 if (result) 1218 bb_error_msg_and_die("%s failed, exit code %d", script_type, result); 1219} 1220 1221/* 1222The policy manual defines what scripts get called when and with 1223what arguments. I realize that busybox does not support all of 1224these scenarios, but it does support some of them; it does not, 1225however, run them with any parameters in run_package_script_or_die(). 1226Here are the scripts: 1227 1228preinst install 1229preinst install <old_version> 1230preinst upgrade <old_version> 1231preinst abort_upgrade <new_version> 1232postinst configure <most_recent_version> 1233postinst abort-upgade <new_version> 1234postinst abort-remove 1235postinst abort-remove in-favour <package> <version> 1236postinst abort-deconfigure in-favor <failed_install_package> removing <conflicting_package> <version> 1237prerm remove 1238prerm upgrade <new_version> 1239prerm failed-upgrade <old_version> 1240prerm remove in-favor <package> <new_version> 1241prerm deconfigure in-favour <package> <version> removing <package> <version> 1242postrm remove 1243postrm purge 1244postrm upgrade <new_version> 1245postrm failed-upgrade <old_version> 1246postrm abort-install 1247postrm abort-install <old_version> 1248postrm abort-upgrade <old_version> 1249postrm disappear <overwriter> <version> 1250*/ 1251static const char *const all_control_files[] = { 1252 "preinst", "postinst", "prerm", "postrm", 1253 "list", "md5sums", "shlibs", "conffiles", 1254 "config", "templates" 1255}; 1256 1257static char **all_control_list(const char *package_name) 1258{ 1259 unsigned i = 0; 1260 char **remove_files; 1261 1262 /* Create a list of all /var/lib/dpkg/info/<package> files */ 1263 remove_files = xzalloc(sizeof(all_control_files) + sizeof(char*)); 1264 while (i < ARRAY_SIZE(all_control_files)) { 1265 remove_files[i] = xasprintf("/var/lib/dpkg/info/%s.%s", 1266 package_name, all_control_files[i]); 1267 i++; 1268 } 1269 1270 return remove_files; 1271} 1272 1273static void free_array(char **array) 1274{ 1275 if (array) { 1276 unsigned i = 0; 1277 while (array[i]) { 1278 free(array[i]); 1279 i++; 1280 } 1281 free(array); 1282 } 1283} 1284 1285/* This function lists information on the installed packages. It loops through 1286 * the status_hashtable to retrieve the info. This results in smaller code than 1287 * scanning the status file. The resulting list, however, is unsorted. 1288 */ 1289static void list_packages(const char *pattern) 1290{ 1291 int i; 1292 1293 puts(" Name Version"); 1294 puts("+++-==============-=============="); 1295 1296 /* go through status hash, dereference package hash and finally strings */ 1297 for (i = 0; i < STATUS_HASH_PRIME+1; i++) { 1298 if (status_hashtable[i]) { 1299 const char *stat_str; /* status string */ 1300 const char *name_str; /* package name */ 1301 const char *vers_str; /* version */ 1302 char s1, s2; /* status abbreviations */ 1303 int spccnt; /* space count */ 1304 int j; 1305 1306 stat_str = name_hashtable[status_hashtable[i]->status]; 1307 name_str = name_hashtable[package_hashtable[status_hashtable[i]->package]->name]; 1308 vers_str = name_hashtable[package_hashtable[status_hashtable[i]->package]->version]; 1309 1310 if (pattern && fnmatch(pattern, name_str, 0) != 0) 1311 continue; 1312 1313 /* get abbreviation for status field 1 */ 1314 s1 = stat_str[0] == 'i' ? 'i' : 'r'; 1315 1316 /* get abbreviation for status field 2 */ 1317 for (j = 0, spccnt = 0; stat_str[j] && spccnt < 2; j++) { 1318 if (stat_str[j] == ' ') spccnt++; 1319 } 1320 s2 = stat_str[j]; 1321 1322 /* print out the line formatted like Debian dpkg */ 1323 printf("%c%c %-14s %s\n", s1, s2, name_str, vers_str); 1324 } 1325 } 1326} 1327 1328static void remove_package(const unsigned package_num, int noisy) 1329{ 1330 const char *package_name = name_hashtable[package_hashtable[package_num]->name]; 1331 const char *package_version = name_hashtable[package_hashtable[package_num]->version]; 1332 const unsigned status_num = search_status_hashtable(package_name); 1333 const int package_name_length = strlen(package_name); 1334 char **remove_files; 1335 char **exclude_files; 1336 char list_name[package_name_length + 25]; 1337 char conffile_name[package_name_length + 30]; 1338 1339 if (noisy) 1340 printf("Removing %s (%s)...\n", package_name, package_version); 1341 1342 /* Run prerm script */ 1343 run_package_script_or_die(package_name, "prerm"); 1344 1345 /* Create a list of files to remove, and a separate list of those to keep */ 1346 sprintf(list_name, "/var/lib/dpkg/info/%s.%s", package_name, "list"); 1347 remove_files = create_list(list_name); 1348 1349 sprintf(conffile_name, "/var/lib/dpkg/info/%s.%s", package_name, "conffiles"); 1350 exclude_files = create_list(conffile_name); 1351 1352 /* Some directories can't be removed straight away, so do multiple passes */ 1353 while (remove_file_array(remove_files, exclude_files)) 1354 continue; 1355 free_array(exclude_files); 1356 free_array(remove_files); 1357 1358 /* Create a list of files in /var/lib/dpkg/info/<package>.* to keep */ 1359 exclude_files = xzalloc(sizeof(exclude_files[0]) * 3); 1360 exclude_files[0] = xstrdup(conffile_name); 1361 exclude_files[1] = xasprintf("/var/lib/dpkg/info/%s.%s", package_name, "postrm"); 1362 1363 /* Create a list of all /var/lib/dpkg/info/<package> files */ 1364 remove_files = all_control_list(package_name); 1365 1366 remove_file_array(remove_files, exclude_files); 1367 free_array(remove_files); 1368 free_array(exclude_files); 1369 1370 /* rename <package>.conffiles to <package>.list 1371 * The conffiles control file isn't required in Debian packages, so don't 1372 * error out if it's missing. */ 1373 rename(conffile_name, list_name); 1374 1375 /* Change package status */ 1376 set_status(status_num, "config-files", 3); 1377} 1378 1379static void purge_package(const unsigned package_num) 1380{ 1381 const char *package_name = name_hashtable[package_hashtable[package_num]->name]; 1382 const char *package_version = name_hashtable[package_hashtable[package_num]->version]; 1383 const unsigned status_num = search_status_hashtable(package_name); 1384 char **remove_files; 1385 char **exclude_files; 1386 char list_name[strlen(package_name) + 25]; 1387 1388 printf("Purging %s (%s)...\n", package_name, package_version); 1389 1390 /* Run prerm script */ 1391 run_package_script_or_die(package_name, "prerm"); 1392 1393 /* Create a list of files to remove */ 1394 sprintf(list_name, "/var/lib/dpkg/info/%s.%s", package_name, "list"); 1395 remove_files = create_list(list_name); 1396 1397 /* Some directories cant be removed straight away, so do multiple passes */ 1398 while (remove_file_array(remove_files, NULL)) 1399 continue; 1400 free_array(remove_files); 1401 1402 /* Create a list of all /var/lib/dpkg/info/<package> files */ 1403 remove_files = all_control_list(package_name); 1404 1405 /* Delete all of them except the postrm script */ 1406 exclude_files = xzalloc(sizeof(exclude_files[0]) * 2); 1407 exclude_files[0] = xasprintf("/var/lib/dpkg/info/%s.%s", package_name, "postrm"); 1408 remove_file_array(remove_files, exclude_files); 1409 free_array(exclude_files); 1410 1411 /* Run and remove postrm script */ 1412 run_package_script_or_die(package_name, "postrm"); 1413 remove_file_array(remove_files, NULL); 1414 1415 free_array(remove_files); 1416 1417 /* Change package status */ 1418 set_status(status_num, "not-installed", 3); 1419} 1420 1421static archive_handle_t *init_archive_deb_ar(const char *filename) 1422{ 1423 archive_handle_t *ar_handle; 1424 1425 /* Setup an ar archive handle that refers to the gzip sub archive */ 1426 ar_handle = init_handle(); 1427 ar_handle->filter = filter_accept_list_reassign; 1428 ar_handle->src_fd = xopen(filename, O_RDONLY); 1429 1430 return ar_handle; 1431} 1432 1433static void init_archive_deb_control(archive_handle_t *ar_handle) 1434{ 1435 archive_handle_t *tar_handle; 1436 1437 /* Setup the tar archive handle */ 1438 tar_handle = init_handle(); 1439 tar_handle->src_fd = ar_handle->src_fd; 1440 1441 /* We don't care about data.tar.* or debian-binary, just control.tar.* */ 1442#if ENABLE_FEATURE_SEAMLESS_GZ 1443 llist_add_to(&(ar_handle->accept), (char*)"control.tar.gz"); 1444#endif 1445#if ENABLE_FEATURE_SEAMLESS_BZ2 1446 llist_add_to(&(ar_handle->accept), (char*)"control.tar.bz2"); 1447#endif 1448 1449 /* Assign the tar handle as a subarchive of the ar handle */ 1450 ar_handle->dpkg__sub_archive = tar_handle; 1451} 1452 1453static void init_archive_deb_data(archive_handle_t *ar_handle) 1454{ 1455 archive_handle_t *tar_handle; 1456 1457 /* Setup the tar archive handle */ 1458 tar_handle = init_handle(); 1459 tar_handle->src_fd = ar_handle->src_fd; 1460 1461 /* We don't care about control.tar.* or debian-binary, just data.tar.* */ 1462#if ENABLE_FEATURE_SEAMLESS_GZ 1463 llist_add_to(&(ar_handle->accept), (char*)"data.tar.gz"); 1464#endif 1465#if ENABLE_FEATURE_SEAMLESS_BZ2 1466 llist_add_to(&(ar_handle->accept), (char*)"data.tar.bz2"); 1467#endif 1468 1469 /* Assign the tar handle as a subarchive of the ar handle */ 1470 ar_handle->dpkg__sub_archive = tar_handle; 1471} 1472 1473static void FAST_FUNC data_extract_to_buffer(archive_handle_t *archive_handle) 1474{ 1475 unsigned size = archive_handle->file_header->size; 1476 1477 archive_handle->dpkg__buffer = xzalloc(size + 1); 1478 xread(archive_handle->src_fd, archive_handle->dpkg__buffer, size); 1479} 1480 1481static char *deb_extract_control_file_to_buffer(archive_handle_t *ar_handle, llist_t *myaccept) 1482{ 1483 ar_handle->dpkg__sub_archive->action_data = data_extract_to_buffer; 1484 ar_handle->dpkg__sub_archive->accept = myaccept; 1485 ar_handle->dpkg__sub_archive->filter = filter_accept_list; 1486 1487 unpack_ar_archive(ar_handle); 1488 close(ar_handle->src_fd); 1489 1490 return ar_handle->dpkg__sub_archive->dpkg__buffer; 1491} 1492 1493static void append_control_file_to_llist(const char *package_name, const char *control_name, llist_t **ll) 1494{ 1495 FILE *fp; 1496 char *filename, *line; 1497 1498 filename = xasprintf("/var/lib/dpkg/info/%s.%s", package_name, control_name); 1499 fp = fopen_for_read(filename); 1500 free(filename); 1501 if (fp != NULL) { 1502 while ((line = xmalloc_fgetline(fp)) != NULL) 1503 llist_add_to(ll, line); 1504 fclose(fp); 1505 } 1506} 1507 1508static char FAST_FUNC filter_rename_config(archive_handle_t *archive_handle) 1509{ 1510 int fd; 1511 char *name_ptr = archive_handle->file_header->name + 1; 1512 1513 /* Is this file marked as config file? */ 1514 if (!find_list_entry(archive_handle->accept, name_ptr)) 1515 return EXIT_SUCCESS; /* no */ 1516 1517 fd = open(name_ptr, O_RDONLY); 1518 if (fd >= 0) { 1519 md5_ctx_t md5; 1520 char *md5line, *buf; 1521 int count; 1522 1523 /* Calculate MD5 of existing file */ 1524 buf = xmalloc(4096); 1525 md5_begin(&md5); 1526 while ((count = safe_read(fd, buf, 4096)) > 0) 1527 md5_hash(buf, count, &md5); 1528 md5_end(buf, &md5); /* using buf as result storage */ 1529 close(fd); 1530 1531 md5line = xmalloc(16 * 2 + 2 + strlen(name_ptr) + 1); 1532 sprintf(bin2hex(md5line, buf, 16), " %s", name_ptr); 1533 free(buf); 1534 1535 /* Is it changed after install? */ 1536 if (find_list_entry(archive_handle->accept, md5line) == NULL) { 1537 printf("Warning: Creating %s as %s.dpkg-new\n", name_ptr, name_ptr); 1538 archive_handle->file_header->name = xasprintf("%s.dpkg-new", archive_handle->file_header->name); 1539 } 1540 free(md5line); 1541 } 1542 return EXIT_SUCCESS; 1543} 1544 1545static void FAST_FUNC data_extract_all_prefix(archive_handle_t *archive_handle) 1546{ 1547 char *name_ptr = archive_handle->file_header->name; 1548 1549 /* Skip all leading "/" */ 1550 while (*name_ptr == '/') 1551 name_ptr++; 1552 /* Skip all leading "./" and "../" */ 1553 while (name_ptr[0] == '.') { 1554 if (name_ptr[1] == '.') 1555 name_ptr++; 1556 if (name_ptr[1] != '/') 1557 break; 1558 name_ptr += 2; 1559 } 1560 1561 if (name_ptr[0] != '\0') { 1562 archive_handle->file_header->name = xasprintf("%s%s", archive_handle->dpkg__buffer, name_ptr); 1563 data_extract_all(archive_handle); 1564 if (fnmatch("*.dpkg-new", archive_handle->file_header->name, 0) == 0) { 1565 /* remove .dpkg-new suffix */ 1566 archive_handle->file_header->name[strlen(archive_handle->file_header->name) - 9] = '\0'; 1567 } 1568 } 1569} 1570 1571enum { 1572 /* Commands */ 1573 OPT_configure = (1 << 0), 1574 OPT_install = (1 << 1), 1575 OPT_list_installed = (1 << 2), 1576 OPT_purge = (1 << 3), 1577 OPT_remove = (1 << 4), 1578 OPT_unpack = (1 << 5), 1579 OPTMASK_cmd = (1 << 6) - 1, 1580 /* Options */ 1581 OPT_force = (1 << 6), 1582 OPT_force_ignore_depends = (1 << 7), 1583 OPT_force_confnew = (1 << 8), 1584 OPT_force_confold = (1 << 9), 1585}; 1586 1587static void unpack_package(deb_file_t *deb_file) 1588{ 1589 const char *package_name = name_hashtable[package_hashtable[deb_file->package]->name]; 1590 const unsigned status_num = search_status_hashtable(package_name); 1591 const unsigned status_package_num = status_hashtable[status_num]->package; 1592 char *info_prefix; 1593 char *list_filename; 1594 archive_handle_t *archive_handle; 1595 FILE *out_stream; 1596 llist_t *accept_list; 1597 llist_t *conffile_list; 1598 int i; 1599 1600 /* If existing version, remove it first */ 1601 conffile_list = NULL; 1602 if (strcmp(name_hashtable[get_status(status_num, 3)], "installed") == 0) { 1603 /* Package is already installed, remove old version first */ 1604 printf("Preparing to replace %s %s (using %s)...\n", package_name, 1605 name_hashtable[package_hashtable[status_package_num]->version], 1606 deb_file->filename); 1607 1608 /* Read md5sums from old package */ 1609 if (!(option_mask32 & OPT_force_confold)) 1610 append_control_file_to_llist(package_name, "md5sums", &conffile_list); 1611 1612 remove_package(status_package_num, 0); 1613 } else { 1614 printf("Unpacking %s (from %s)...\n", package_name, deb_file->filename); 1615 } 1616 1617 /* Extract control.tar.gz to /var/lib/dpkg/info/<package>.filename */ 1618 info_prefix = xasprintf("/var/lib/dpkg/info/%s.%s", package_name, ""); 1619 archive_handle = init_archive_deb_ar(deb_file->filename); 1620 init_archive_deb_control(archive_handle); 1621 1622 accept_list = NULL; 1623 i = 0; 1624 while (i < ARRAY_SIZE(all_control_files)) { 1625 char *c = xasprintf("./%s", all_control_files[i]); 1626 llist_add_to(&accept_list, c); 1627 i++; 1628 } 1629 archive_handle->dpkg__sub_archive->accept = accept_list; 1630 archive_handle->dpkg__sub_archive->filter = filter_accept_list; 1631 archive_handle->dpkg__sub_archive->action_data = data_extract_all_prefix; 1632 archive_handle->dpkg__sub_archive->dpkg__buffer = info_prefix; 1633 archive_handle->dpkg__sub_archive->ah_flags |= ARCHIVE_UNLINK_OLD; 1634 unpack_ar_archive(archive_handle); 1635 1636 /* Run the preinst prior to extracting */ 1637 run_package_script_or_die(package_name, "preinst"); 1638 1639 /* Don't overwrite existing config files */ 1640 if (!(option_mask32 & OPT_force_confnew)) 1641 append_control_file_to_llist(package_name, "conffiles", &conffile_list); 1642 1643 /* Extract data.tar.gz to the root directory */ 1644 archive_handle = init_archive_deb_ar(deb_file->filename); 1645 init_archive_deb_data(archive_handle); 1646 archive_handle->dpkg__sub_archive->accept = conffile_list; 1647 archive_handle->dpkg__sub_archive->filter = filter_rename_config; 1648 archive_handle->dpkg__sub_archive->action_data = data_extract_all_prefix; 1649 archive_handle->dpkg__sub_archive->dpkg__buffer = (char*)"/"; /* huh? */ 1650 archive_handle->dpkg__sub_archive->ah_flags |= ARCHIVE_UNLINK_OLD; 1651 unpack_ar_archive(archive_handle); 1652 1653 /* Create the list file */ 1654 list_filename = xasprintf("/var/lib/dpkg/info/%s.%s", package_name, "list"); 1655 out_stream = xfopen_for_write(list_filename); 1656 while (archive_handle->dpkg__sub_archive->passed) { 1657 /* the leading . has been stripped by data_extract_all_prefix already */ 1658 fputs(archive_handle->dpkg__sub_archive->passed->data, out_stream); 1659 fputc('\n', out_stream); 1660 archive_handle->dpkg__sub_archive->passed = archive_handle->dpkg__sub_archive->passed->link; 1661 } 1662 fclose(out_stream); 1663 1664 /* change status */ 1665 set_status(status_num, "install", 1); 1666 set_status(status_num, "unpacked", 3); 1667 1668 free(info_prefix); 1669 free(list_filename); 1670} 1671 1672static void configure_package(deb_file_t *deb_file) 1673{ 1674 const char *package_name = name_hashtable[package_hashtable[deb_file->package]->name]; 1675 const char *package_version = name_hashtable[package_hashtable[deb_file->package]->version]; 1676 const int status_num = search_status_hashtable(package_name); 1677 1678 printf("Setting up %s (%s)...\n", package_name, package_version); 1679 1680 /* Run the postinst script */ 1681 /* TODO: handle failure gracefully */ 1682 run_package_script_or_die(package_name, "postinst"); 1683 1684 /* Change status to reflect success */ 1685 set_status(status_num, "install", 1); 1686 set_status(status_num, "installed", 3); 1687} 1688 1689int dpkg_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 1690int dpkg_main(int argc UNUSED_PARAM, char **argv) 1691{ 1692 deb_file_t **deb_file = NULL; 1693 status_node_t *status_node; 1694 char *str_f; 1695 int opt; 1696 int package_num; 1697 int deb_count = 0; 1698 int state_status; 1699 int status_num; 1700 int i; 1701#if ENABLE_LONG_OPTS 1702 static const char dpkg_longopts[] ALIGN1 = 1703// FIXME: we use -C non-compatibly, should be: 1704// "-C|--audit Check for broken package(s)" 1705 "configure\0" No_argument "C" 1706 "force\0" Required_argument "F" 1707 "install\0" No_argument "i" 1708 "list\0" No_argument "l" 1709 "purge\0" No_argument "P" 1710 "remove\0" No_argument "r" 1711 "unpack\0" No_argument "u" 1712 "force-depends\0" No_argument "\xff" 1713 "force-confnew\0" No_argument "\xfe" 1714 "force-confold\0" No_argument "\xfd" 1715 ; 1716#endif 1717 1718 INIT_G(); 1719 1720 IF_LONG_OPTS(applet_long_options = dpkg_longopts); 1721 opt = getopt32(argv, "CilPruF:", &str_f); 1722 argv += optind; 1723 //if (opt & OPT_configure) ... // -C 1724 if (opt & OPT_force) { // -F (--force in official dpkg) 1725 if (strcmp(str_f, "depends") == 0) 1726 opt |= OPT_force_ignore_depends; 1727 else if (strcmp(str_f, "confnew") == 0) 1728 opt |= OPT_force_confnew; 1729 else if (strcmp(str_f, "confold") == 0) 1730 opt |= OPT_force_confold; 1731 else 1732 bb_show_usage(); 1733 option_mask32 = opt; 1734 } 1735 //if (opt & OPT_install) ... // -i 1736 //if (opt & OPT_list_installed) ... // -l 1737 //if (opt & OPT_purge) ... // -P 1738 //if (opt & OPT_remove) ... // -r 1739 //if (opt & OPT_unpack) ... // -u (--unpack in official dpkg) 1740 if (!(opt & OPTMASK_cmd) /* no cmd */ 1741 || ((opt & OPTMASK_cmd) & ((opt & OPTMASK_cmd)-1)) /* more than one cmd */ 1742 ) { 1743 bb_show_usage(); 1744 } 1745 1746/* puts("(Reading database ... xxxxx files and directories installed.)"); */ 1747 index_status_file("/var/lib/dpkg/status"); 1748 1749 /* if the list action was given print the installed packages and exit */ 1750 if (opt & OPT_list_installed) { 1751 list_packages(argv[0]); /* param can be NULL */ 1752 return EXIT_SUCCESS; 1753 } 1754 1755 /* Read arguments and store relevant info in structs */ 1756 while (*argv) { 1757 /* deb_count = nb_elem - 1 and we need nb_elem + 1 to allocate terminal node [NULL pointer] */ 1758 deb_file = xrealloc_vector(deb_file, 2, deb_count); 1759 deb_file[deb_count] = xzalloc(sizeof(deb_file[0][0])); 1760 if (opt & (OPT_install | OPT_unpack)) { 1761 /* -i/-u: require filename */ 1762 archive_handle_t *archive_handle; 1763 llist_t *control_list = NULL; 1764 1765 /* Extract the control file */ 1766 llist_add_to(&control_list, (char*)"./control"); 1767 archive_handle = init_archive_deb_ar(argv[0]); 1768 init_archive_deb_control(archive_handle); 1769 deb_file[deb_count]->control_file = deb_extract_control_file_to_buffer(archive_handle, control_list); 1770 if (deb_file[deb_count]->control_file == NULL) { 1771 bb_error_msg_and_die("can't extract control file"); 1772 } 1773 deb_file[deb_count]->filename = xstrdup(argv[0]); 1774 package_num = fill_package_struct(deb_file[deb_count]->control_file); 1775 1776 if (package_num == -1) { 1777 bb_error_msg("invalid control file in %s", argv[0]); 1778 argv++; 1779 continue; 1780 } 1781 deb_file[deb_count]->package = (unsigned) package_num; 1782 1783 /* Add the package to the status hashtable */ 1784 if (opt & (OPT_unpack | OPT_install)) { 1785 /* Try and find a currently installed version of this package */ 1786 status_num = search_status_hashtable(name_hashtable[package_hashtable[deb_file[deb_count]->package]->name]); 1787 /* If no previous entry was found initialise a new entry */ 1788 if (status_hashtable[status_num] == NULL 1789 || status_hashtable[status_num]->status == 0 1790 ) { 1791 status_node = xmalloc(sizeof(status_node_t)); 1792 status_node->package = deb_file[deb_count]->package; 1793 /* reinstreq isnt changed to "ok" until the package control info 1794 * is written to the status file*/ 1795 status_node->status = search_name_hashtable("install reinstreq not-installed"); 1796 status_hashtable[status_num] = status_node; 1797 } else { 1798 set_status(status_num, "install", 1); 1799 set_status(status_num, "reinstreq", 2); 1800 } 1801 } 1802 } else if (opt & (OPT_configure | OPT_purge | OPT_remove)) { 1803 /* -C/-p/-r: require package name */ 1804 deb_file[deb_count]->package = search_package_hashtable( 1805 search_name_hashtable(argv[0]), 1806 search_name_hashtable("ANY"), VER_ANY); 1807 if (package_hashtable[deb_file[deb_count]->package] == NULL) { 1808 bb_error_msg_and_die("package %s is uninstalled or unknown", argv[0]); 1809 } 1810 package_num = deb_file[deb_count]->package; 1811 status_num = search_status_hashtable(name_hashtable[package_hashtable[package_num]->name]); 1812 state_status = get_status(status_num, 3); 1813 1814 /* check package status is "installed" */ 1815 if (opt & OPT_remove) { 1816 if (strcmp(name_hashtable[state_status], "not-installed") == 0 1817 || strcmp(name_hashtable[state_status], "config-files") == 0 1818 ) { 1819 bb_error_msg_and_die("%s is already removed", name_hashtable[package_hashtable[package_num]->name]); 1820 } 1821 set_status(status_num, "deinstall", 1); 1822 } else if (opt & OPT_purge) { 1823 /* if package status is "conf-files" then its ok */ 1824 if (strcmp(name_hashtable[state_status], "not-installed") == 0) { 1825 bb_error_msg_and_die("%s is already purged", name_hashtable[package_hashtable[package_num]->name]); 1826 } 1827 set_status(status_num, "purge", 1); 1828 } 1829 } 1830 deb_count++; 1831 argv++; 1832 } 1833 if (!deb_count) 1834 bb_error_msg_and_die("no package files specified"); 1835 deb_file[deb_count] = NULL; 1836 1837 /* Check that the deb file arguments are installable */ 1838 if (!(opt & OPT_force_ignore_depends)) { 1839 if (!check_deps(deb_file, 0 /*, deb_count*/)) { 1840 bb_error_msg_and_die("dependency check failed"); 1841 } 1842 } 1843 1844 /* TODO: install or remove packages in the correct dependency order */ 1845 for (i = 0; i < deb_count; i++) { 1846 /* Remove or purge packages */ 1847 if (opt & OPT_remove) { 1848 remove_package(deb_file[i]->package, 1); 1849 } 1850 else if (opt & OPT_purge) { 1851 purge_package(deb_file[i]->package); 1852 } 1853 else if (opt & OPT_unpack) { 1854 unpack_package(deb_file[i]); 1855 } 1856 else if (opt & OPT_install) { 1857 unpack_package(deb_file[i]); 1858 /* package is configured in second pass below */ 1859 } 1860 else if (opt & OPT_configure) { 1861 configure_package(deb_file[i]); 1862 } 1863 } 1864 /* configure installed packages */ 1865 if (opt & OPT_install) { 1866 for (i = 0; i < deb_count; i++) 1867 configure_package(deb_file[i]); 1868 } 1869 1870 write_status_file(deb_file); 1871 1872 if (ENABLE_FEATURE_CLEAN_UP) { 1873 for (i = 0; i < deb_count; i++) { 1874 free(deb_file[i]->control_file); 1875 free(deb_file[i]->filename); 1876 free(deb_file[i]); 1877 } 1878 1879 free(deb_file); 1880 1881 for (i = 0; i < NAME_HASH_PRIME; i++) { 1882 free(name_hashtable[i]); 1883 } 1884 1885 for (i = 0; i < PACKAGE_HASH_PRIME; i++) { 1886 free_package(package_hashtable[i]); 1887 } 1888 1889 for (i = 0; i < STATUS_HASH_PRIME; i++) { 1890 free(status_hashtable[i]); 1891 } 1892 1893 free(status_hashtable); 1894 free(package_hashtable); 1895 free(name_hashtable); 1896 } 1897 1898 return EXIT_SUCCESS; 1899} 1900