24 |
* |
* |
25 |
*/ |
*/ |
26 |
|
|
27 |
#include "busybox.h" |
#include "libbb.h" |
28 |
|
#include <fnmatch.h> |
29 |
#include "unarchive.h" |
#include "unarchive.h" |
30 |
|
|
31 |
/* note: if you vary hash_prime sizes be aware, |
/* note: if you vary hash_prime sizes be aware, |
54 |
* and available file */ |
* and available file */ |
55 |
#define PACKAGE_HASH_PRIME 10007 |
#define PACKAGE_HASH_PRIME 10007 |
56 |
typedef struct edge_s { |
typedef struct edge_s { |
57 |
unsigned operator:3; |
unsigned operator:4; /* was:3 */ |
58 |
unsigned type:4; |
unsigned type:4; |
59 |
unsigned name:14; |
unsigned name:16; /* was:14 */ |
60 |
unsigned version:14; |
unsigned version:16; /* was:14 */ |
61 |
} edge_t; |
} edge_t; |
62 |
|
|
63 |
typedef struct common_node_s { |
typedef struct common_node_s { |
64 |
unsigned name:14; |
unsigned name:16; /* was:14 */ |
65 |
unsigned version:14; |
unsigned version:16; /* was:14 */ |
66 |
unsigned num_of_edges:14; |
unsigned num_of_edges:16; /* was:14 */ |
67 |
edge_t **edge; |
edge_t **edge; |
68 |
} common_node_t; |
} common_node_t; |
69 |
|
|
72 |
* likely to be installed at any one time, so there is a bit of leeway here */ |
* likely to be installed at any one time, so there is a bit of leeway here */ |
73 |
#define STATUS_HASH_PRIME 8191 |
#define STATUS_HASH_PRIME 8191 |
74 |
typedef struct status_node_s { |
typedef struct status_node_s { |
75 |
unsigned package:14; /* has to fit PACKAGE_HASH_PRIME */ |
unsigned package:16; /* was:14 */ /* has to fit PACKAGE_HASH_PRIME */ |
76 |
unsigned status:14; /* has to fit STATUS_HASH_PRIME */ |
unsigned status:16; /* was:14 */ /* has to fit STATUS_HASH_PRIME */ |
77 |
} status_node_t; |
} status_node_t; |
78 |
|
|
79 |
/* Were statically declared here, but such a big bss is nommu-unfriendly */ |
|
80 |
static char **name_hashtable; /* [NAME_HASH_PRIME + 1] */ |
/* Globals */ |
81 |
static common_node_t **package_hashtable; /* [PACKAGE_HASH_PRIME + 1] */ |
struct globals { |
82 |
static status_node_t **status_hashtable; /* [STATUS_HASH_PRIME + 1] */ |
char *name_hashtable[NAME_HASH_PRIME + 1]; |
83 |
|
common_node_t *package_hashtable[PACKAGE_HASH_PRIME + 1]; |
84 |
|
status_node_t *status_hashtable[STATUS_HASH_PRIME + 1]; |
85 |
|
}; |
86 |
|
#define G (*ptr_to_globals) |
87 |
|
#define name_hashtable (G.name_hashtable ) |
88 |
|
#define package_hashtable (G.package_hashtable) |
89 |
|
#define status_hashtable (G.status_hashtable ) |
90 |
|
#define INIT_G() do { \ |
91 |
|
SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \ |
92 |
|
} while (0) |
93 |
|
|
94 |
|
|
95 |
/* Even numbers are for 'extras', like ored dependencies or null */ |
/* Even numbers are for 'extras', like ored dependencies or null */ |
96 |
enum edge_type_e { |
enum edge_type_e { |
119 |
typedef struct deb_file_s { |
typedef struct deb_file_s { |
120 |
char *control_file; |
char *control_file; |
121 |
char *filename; |
char *filename; |
122 |
unsigned package:14; |
unsigned package:16; /* was:14 */ |
123 |
} deb_file_t; |
} deb_file_t; |
124 |
|
|
125 |
|
|
126 |
static void make_hash(const char *key, unsigned *start, unsigned *decrement, const int hash_prime) |
static void make_hash(const char *key, unsigned *start, unsigned *decrement, const int hash_prime) |
127 |
{ |
{ |
128 |
unsigned long int hash_num = key[0]; |
unsigned long hash_num = key[0]; |
129 |
int len = strlen(key); |
int len = strlen(key); |
130 |
int i; |
int i; |
131 |
|
|
136 |
* shift amount is mod 24 because long int is 32 bit and data |
* shift amount is mod 24 because long int is 32 bit and data |
137 |
* to be shifted is 8, don't want to shift data to where it has |
* to be shifted is 8, don't want to shift data to where it has |
138 |
* no effect*/ |
* no effect*/ |
139 |
hash_num += ((key[i] + key[i-1]) << ((key[i] * i) % 24)); |
hash_num += (key[i] + key[i-1]) << ((key[i] * i) % 24); |
140 |
} |
} |
141 |
*start = (unsigned) hash_num % hash_prime; |
*start = (unsigned) hash_num % hash_prime; |
142 |
*decrement = (unsigned) 1 + (hash_num % (hash_prime - 1)); |
*decrement = (unsigned) 1 + (hash_num % (hash_prime - 1)); |
145 |
/* this adds the key to the hash table */ |
/* this adds the key to the hash table */ |
146 |
static int search_name_hashtable(const char *key) |
static int search_name_hashtable(const char *key) |
147 |
{ |
{ |
148 |
unsigned probe_address = 0; |
unsigned probe_address; |
149 |
unsigned probe_decrement = 0; |
unsigned probe_decrement; |
150 |
|
|
151 |
make_hash(key, &probe_address, &probe_decrement, NAME_HASH_PRIME); |
make_hash(key, &probe_address, &probe_decrement, NAME_HASH_PRIME); |
152 |
while (name_hashtable[probe_address] != NULL) { |
while (name_hashtable[probe_address] != NULL) { |
167 |
*/ |
*/ |
168 |
static unsigned search_status_hashtable(const char *key) |
static unsigned search_status_hashtable(const char *key) |
169 |
{ |
{ |
170 |
unsigned probe_address = 0; |
unsigned probe_address; |
171 |
unsigned probe_decrement = 0; |
unsigned probe_decrement; |
172 |
|
|
173 |
make_hash(key, &probe_address, &probe_decrement, STATUS_HASH_PRIME); |
make_hash(key, &probe_address, &probe_decrement, STATUS_HASH_PRIME); |
174 |
while (status_hashtable[probe_address] != NULL) { |
while (status_hashtable[probe_address] != NULL) { |
324 |
return FALSE; |
return FALSE; |
325 |
} |
} |
326 |
|
|
|
|
|
327 |
static int search_package_hashtable(const unsigned name, const unsigned version, const unsigned operator) |
static int search_package_hashtable(const unsigned name, const unsigned version, const unsigned operator) |
328 |
{ |
{ |
329 |
unsigned probe_address = 0; |
unsigned probe_address; |
330 |
unsigned probe_decrement = 0; |
unsigned probe_decrement; |
331 |
|
|
332 |
make_hash(name_hashtable[name], &probe_address, &probe_decrement, PACKAGE_HASH_PRIME); |
make_hash(name_hashtable[name], &probe_address, &probe_decrement, PACKAGE_HASH_PRIME); |
333 |
while (package_hashtable[probe_address] != NULL) { |
while (package_hashtable[probe_address] != NULL) { |
363 |
* FIXME: I don't think this is very efficient, but I thought I'd keep |
* FIXME: I don't think this is very efficient, but I thought I'd keep |
364 |
* it simple for now until it proves to be a problem. |
* it simple for now until it proves to be a problem. |
365 |
*/ |
*/ |
366 |
static int search_for_provides(int needle, int start_at) { |
static int search_for_provides(int needle, int start_at) |
367 |
|
{ |
368 |
int i, j; |
int i, j; |
369 |
common_node_t *p; |
common_node_t *p; |
370 |
for (i = start_at + 1; i < PACKAGE_HASH_PRIME; i++) { |
for (i = start_at + 1; i < PACKAGE_HASH_PRIME; i++) { |
383 |
*/ |
*/ |
384 |
static void add_edge_to_node(common_node_t *node, edge_t *edge) |
static void add_edge_to_node(common_node_t *node, edge_t *edge) |
385 |
{ |
{ |
386 |
node->num_of_edges++; |
node->edge = xrealloc_vector(node->edge, 2, node->num_of_edges); |
387 |
node->edge = xrealloc(node->edge, sizeof(edge_t) * (node->num_of_edges + 1)); |
node->edge[node->num_of_edges++] = edge; |
|
node->edge[node->num_of_edges - 1] = edge; |
|
388 |
} |
} |
389 |
|
|
390 |
/* |
/* |
420 |
if ((edge_type == EDGE_DEPENDS || edge_type == EDGE_PRE_DEPENDS) |
if ((edge_type == EDGE_DEPENDS || edge_type == EDGE_PRE_DEPENDS) |
421 |
&& (strcmp(field, field2) != 0) |
&& (strcmp(field, field2) != 0) |
422 |
) { |
) { |
423 |
or_edge = xmalloc(sizeof(edge_t)); |
or_edge = xzalloc(sizeof(edge_t)); |
424 |
or_edge->type = edge_type + 1; |
or_edge->type = edge_type + 1; |
425 |
or_edge->name = search_name_hashtable(field); |
or_edge->name = search_name_hashtable(field); |
426 |
or_edge->version = 0; // tracks the number of altenatives |
//or_edge->version = 0; // tracks the number of alternatives |
427 |
add_edge_to_node(parent_node, or_edge); |
add_edge_to_node(parent_node, or_edge); |
428 |
} |
} |
429 |
|
|
442 |
edge->version = search_name_hashtable("ANY"); |
edge->version = search_name_hashtable("ANY"); |
443 |
} else { |
} else { |
444 |
/* Skip leading ' ' or '(' */ |
/* Skip leading ' ' or '(' */ |
445 |
version += strspn(field2, " ("); |
version += strspn(version, " ("); |
446 |
/* Calculate length of any operator characters */ |
/* Calculate length of any operator characters */ |
447 |
offset_ch = strspn(version, "<=>"); |
offset_ch = strspn(version, "<=>"); |
448 |
/* Determine operator */ |
/* Determine operator */ |
449 |
if (offset_ch > 0) { |
if (offset_ch > 0) { |
450 |
if (strncmp(version, "=", offset_ch) == 0) { |
if (strncmp(version, "=", offset_ch) == 0) { |
451 |
edge->operator = VER_EQUAL; |
edge->operator = VER_EQUAL; |
452 |
} |
} else if (strncmp(version, "<<", offset_ch) == 0) { |
|
else if (strncmp(version, "<<", offset_ch) == 0) { |
|
453 |
edge->operator = VER_LESS; |
edge->operator = VER_LESS; |
454 |
} |
} else if (strncmp(version, "<=", offset_ch) == 0) { |
|
else if (strncmp(version, "<=", offset_ch) == 0) { |
|
455 |
edge->operator = VER_LESS_EQUAL; |
edge->operator = VER_LESS_EQUAL; |
456 |
} |
} else if (strncmp(version, ">>", offset_ch) == 0) { |
|
else if (strncmp(version, ">>", offset_ch) == 0) { |
|
457 |
edge->operator = VER_MORE; |
edge->operator = VER_MORE; |
458 |
} |
} else if (strncmp(version, ">=", offset_ch) == 0) { |
|
else if (strncmp(version, ">=", offset_ch) == 0) { |
|
459 |
edge->operator = VER_MORE_EQUAL; |
edge->operator = VER_MORE_EQUAL; |
460 |
} else { |
} else { |
461 |
bb_error_msg_and_die("illegal operator"); |
bb_error_msg_and_die("illegal operator"); |
479 |
or_edge->version++; |
or_edge->version++; |
480 |
|
|
481 |
add_edge_to_node(parent_node, edge); |
add_edge_to_node(parent_node, edge); |
482 |
} while ((field2 = strtok_r(NULL, "|", &line_ptr2)) != NULL); |
field2 = strtok_r(NULL, "|", &line_ptr2); |
483 |
|
} while (field2 != NULL); |
484 |
|
|
485 |
free(line2); |
free(line2); |
486 |
} while ((field = strtok_r(NULL, ",", &line_ptr1)) != NULL); |
field = strtok_r(NULL, ",", &line_ptr1); |
487 |
|
} while (field != NULL); |
488 |
|
|
489 |
free(line); |
free(line); |
490 |
} |
} |
491 |
|
|
588 |
|
|
589 |
static unsigned fill_package_struct(char *control_buffer) |
static unsigned fill_package_struct(char *control_buffer) |
590 |
{ |
{ |
591 |
static const char *const field_names[] = { "Package", "Version", |
static const char field_names[] ALIGN1 = |
592 |
"Pre-Depends", "Depends","Replaces", "Provides", |
"Package\0""Version\0" |
593 |
"Conflicts", "Suggests", "Recommends", "Enhances", 0 |
"Pre-Depends\0""Depends\0""Replaces\0""Provides\0" |
594 |
}; |
"Conflicts\0""Suggests\0""Recommends\0""Enhances\0"; |
595 |
|
|
596 |
common_node_t *new_node = xzalloc(sizeof(common_node_t)); |
common_node_t *new_node = xzalloc(sizeof(common_node_t)); |
597 |
char *field_name; |
char *field_name; |
608 |
&field_name, &field_value); |
&field_name, &field_value); |
609 |
|
|
610 |
if (field_name == NULL) { |
if (field_name == NULL) { |
611 |
goto fill_package_struct_cleanup; /* Oh no, the dreaded goto statement ! */ |
goto fill_package_struct_cleanup; |
612 |
} |
} |
613 |
|
|
614 |
field_num = index_in_str_array(field_names, field_name); |
field_num = index_in_strings(field_names, field_name); |
615 |
switch (field_num) { |
switch (field_num) { |
616 |
case 0: /* Package */ |
case 0: /* Package */ |
617 |
new_node->name = search_name_hashtable(field_value); |
new_node->name = search_name_hashtable(field_value); |
654 |
return -1; |
return -1; |
655 |
} |
} |
656 |
num = search_package_hashtable(new_node->name, new_node->version, VER_EQUAL); |
num = search_package_hashtable(new_node->name, new_node->version, VER_EQUAL); |
657 |
if (package_hashtable[num] == NULL) { |
free_package(package_hashtable[num]); |
658 |
package_hashtable[num] = new_node; |
package_hashtable[num] = new_node; |
|
} else { |
|
|
free_package(new_node); |
|
|
} |
|
659 |
return num; |
return num; |
660 |
} |
} |
661 |
|
|
714 |
new_status = xasprintf("%s %s %s", name_hashtable[want], name_hashtable[flag], name_hashtable[status]); |
new_status = xasprintf("%s %s %s", name_hashtable[want], name_hashtable[flag], name_hashtable[status]); |
715 |
status_hashtable[status_node_num]->status = search_name_hashtable(new_status); |
status_hashtable[status_node_num]->status = search_name_hashtable(new_status); |
716 |
free(new_status); |
free(new_status); |
|
return; |
|
717 |
} |
} |
718 |
|
|
719 |
static const char *describe_status(int status_num) { |
static const char *describe_status(int status_num) |
720 |
int status_want, status_state ; |
{ |
721 |
|
int status_want, status_state; |
722 |
if (status_hashtable[status_num] == NULL || status_hashtable[status_num]->status == 0) |
if (status_hashtable[status_num] == NULL || status_hashtable[status_num]->status == 0) |
723 |
return "is not installed or flagged to be installed\n"; |
return "is not installed or flagged to be installed"; |
724 |
|
|
725 |
status_want = get_status(status_num, 1); |
status_want = get_status(status_num, 1); |
726 |
status_state = get_status(status_num, 3); |
status_state = get_status(status_num, 3); |
733 |
if (status_want == search_name_hashtable("purge")) |
if (status_want == search_name_hashtable("purge")) |
734 |
return "is marked to be purged"; |
return "is marked to be purged"; |
735 |
} |
} |
736 |
if (status_want == search_name_hashtable("unknown")) |
if (status_want == search_name_hashtable("unknown")) |
737 |
return "is in an indeterminate state"; |
return "is in an indeterminate state"; |
738 |
if (status_want == search_name_hashtable("install")) |
if (status_want == search_name_hashtable("install")) |
739 |
return "is marked to be installed"; |
return "is marked to be installed"; |
741 |
return "is not installed or flagged to be installed"; |
return "is not installed or flagged to be installed"; |
742 |
} |
} |
743 |
|
|
|
|
|
744 |
static void index_status_file(const char *filename) |
static void index_status_file(const char *filename) |
745 |
{ |
{ |
746 |
FILE *status_file; |
FILE *status_file; |
749 |
status_node_t *status_node = NULL; |
status_node_t *status_node = NULL; |
750 |
unsigned status_num; |
unsigned status_num; |
751 |
|
|
752 |
status_file = xfopen(filename, "r"); |
status_file = xfopen_for_read(filename); |
753 |
while ((control_buffer = xmalloc_fgets_str(status_file, "\n\n")) != NULL) { |
while ((control_buffer = xmalloc_fgetline_str(status_file, "\n\n")) != NULL) { |
754 |
const unsigned package_num = fill_package_struct(control_buffer); |
const unsigned package_num = fill_package_struct(control_buffer); |
755 |
if (package_num != -1) { |
if (package_num != -1) { |
756 |
status_node = xmalloc(sizeof(status_node_t)); |
status_node = xmalloc(sizeof(status_node_t)); |
770 |
free(control_buffer); |
free(control_buffer); |
771 |
} |
} |
772 |
fclose(status_file); |
fclose(status_file); |
|
return; |
|
773 |
} |
} |
774 |
|
|
775 |
static void write_buffer_no_status(FILE *new_status_file, const char *control_buffer) |
static void write_buffer_no_status(FILE *new_status_file, const char *control_buffer) |
786 |
fprintf(new_status_file, "%s: %s\n", name, value); |
fprintf(new_status_file, "%s: %s\n", name, value); |
787 |
} |
} |
788 |
} |
} |
|
return; |
|
789 |
} |
} |
790 |
|
|
791 |
/* This could do with a cleanup */ |
/* This could do with a cleanup */ |
792 |
static void write_status_file(deb_file_t **deb_file) |
static void write_status_file(deb_file_t **deb_file) |
793 |
{ |
{ |
794 |
FILE *old_status_file = xfopen("/var/lib/dpkg/status", "r"); |
FILE *old_status_file = xfopen_for_read("/var/lib/dpkg/status"); |
795 |
FILE *new_status_file = xfopen("/var/lib/dpkg/status.udeb", "w"); |
FILE *new_status_file = xfopen_for_write("/var/lib/dpkg/status.udeb"); |
796 |
char *package_name; |
char *package_name; |
797 |
char *status_from_file; |
char *status_from_file; |
798 |
char *control_buffer = NULL; |
char *control_buffer = NULL; |
803 |
int i = 0; |
int i = 0; |
804 |
|
|
805 |
/* Update previously known packages */ |
/* Update previously known packages */ |
806 |
while ((control_buffer = xmalloc_fgets_str(old_status_file, "\n\n")) != NULL) { |
while ((control_buffer = xmalloc_fgetline_str(old_status_file, "\n\n")) != NULL) { |
807 |
if ((tmp_string = strstr(control_buffer, "Package:")) == NULL) { |
tmp_string = strstr(control_buffer, "Package:"); |
808 |
|
if (tmp_string == NULL) { |
809 |
continue; |
continue; |
810 |
} |
} |
811 |
|
|
830 |
if (strcmp(status_from_file, status_from_hashtable) != 0) { |
if (strcmp(status_from_file, status_from_hashtable) != 0) { |
831 |
/* New status isnt exactly the same as old status */ |
/* New status isnt exactly the same as old status */ |
832 |
const int state_status = get_status(status_num, 3); |
const int state_status = get_status(status_num, 3); |
833 |
if ((strcmp("installed", name_hashtable[state_status]) == 0) || |
if ((strcmp("installed", name_hashtable[state_status]) == 0) |
834 |
(strcmp("unpacked", name_hashtable[state_status]) == 0)) { |
|| (strcmp("unpacked", name_hashtable[state_status]) == 0) |
835 |
|
) { |
836 |
/* We need to add the control file from the package */ |
/* We need to add the control file from the package */ |
837 |
i = 0; |
i = 0; |
838 |
while (deb_file[i] != NULL) { |
while (deb_file[i] != NULL) { |
897 |
} |
} |
898 |
} |
} |
899 |
/* If the package from the status file wasnt handle above, do it now*/ |
/* If the package from the status file wasnt handle above, do it now*/ |
900 |
if (! write_flag) { |
if (!write_flag) { |
901 |
fprintf(new_status_file, "%s\n\n", control_buffer); |
fprintf(new_status_file, "%s\n\n", control_buffer); |
902 |
} |
} |
903 |
|
|
918 |
fclose(old_status_file); |
fclose(old_status_file); |
919 |
fclose(new_status_file); |
fclose(new_status_file); |
920 |
|
|
|
|
|
921 |
/* Create a separate backfile to dpkg */ |
/* Create a separate backfile to dpkg */ |
922 |
if (rename("/var/lib/dpkg/status", "/var/lib/dpkg/status.udeb.bak") == -1) { |
if (rename("/var/lib/dpkg/status", "/var/lib/dpkg/status.udeb.bak") == -1) { |
923 |
struct stat stat_buf; |
if (errno != ENOENT) |
924 |
xstat("/var/lib/dpkg/status", &stat_buf); |
bb_error_msg_and_die("cannot create backup status file"); |
925 |
/* Its ok if renaming the status file fails because status |
/* Its ok if renaming the status file fails because status |
926 |
* file doesnt exist, maybe we are starting from scratch */ |
* file doesnt exist, maybe we are starting from scratch */ |
927 |
bb_error_msg("no status file found, creating new one"); |
bb_error_msg("no status file found, creating new one"); |
928 |
} |
} |
929 |
|
|
930 |
if (rename("/var/lib/dpkg/status.udeb", "/var/lib/dpkg/status") == -1) { |
xrename("/var/lib/dpkg/status.udeb", "/var/lib/dpkg/status"); |
|
bb_error_msg_and_die("DANGER: cannot create status file, " |
|
|
"you need to manually repair your status file"); |
|
|
} |
|
931 |
} |
} |
932 |
|
|
933 |
/* This function returns TRUE if the given package can satisfy a |
/* This function returns TRUE if the given package can satisfy a |
954 |
return 0; |
return 0; |
955 |
} |
} |
956 |
|
|
957 |
static int check_deps(deb_file_t **deb_file, int deb_start, int dep_max_count) |
static int check_deps(deb_file_t **deb_file, int deb_start /*, int dep_max_count - ?? */) |
958 |
{ |
{ |
959 |
int *conflicts = NULL; |
int *conflicts = NULL; |
960 |
int conflicts_num = 0; |
int conflicts_num = 0; |
972 |
* installed package for conflicts*/ |
* installed package for conflicts*/ |
973 |
while (deb_file[i] != NULL) { |
while (deb_file[i] != NULL) { |
974 |
const unsigned package_num = deb_file[i]->package; |
const unsigned package_num = deb_file[i]->package; |
975 |
conflicts = xrealloc(conflicts, sizeof(int) * (conflicts_num + 1)); |
conflicts = xrealloc_vector(conflicts, 2, conflicts_num); |
976 |
conflicts[conflicts_num] = package_num; |
conflicts[conflicts_num] = package_num; |
977 |
conflicts_num++; |
conflicts_num++; |
978 |
/* add provides to conflicts list */ |
/* add provides to conflicts list */ |
989 |
new_node->version = package_hashtable[package_num]->edge[j]->version; |
new_node->version = package_hashtable[package_num]->edge[j]->version; |
990 |
package_hashtable[conflicts_package_num] = new_node; |
package_hashtable[conflicts_package_num] = new_node; |
991 |
} |
} |
992 |
conflicts = xrealloc(conflicts, sizeof(int) * (conflicts_num + 1)); |
conflicts = xrealloc_vector(conflicts, 2, conflicts_num); |
993 |
conflicts[conflicts_num] = conflicts_package_num; |
conflicts[conflicts_num] = conflicts_package_num; |
994 |
conflicts_num++; |
conflicts_num++; |
995 |
} |
} |
1074 |
const edge_t *package_edge = package_node->edge[j]; |
const edge_t *package_edge = package_node->edge[j]; |
1075 |
unsigned package_num; |
unsigned package_num; |
1076 |
|
|
1077 |
if (package_edge->type == EDGE_OR_PRE_DEPENDS || |
if (package_edge->type == EDGE_OR_PRE_DEPENDS |
1078 |
package_edge->type == EDGE_OR_DEPENDS) { /* start an EDGE_OR_ list */ |
|| package_edge->type == EDGE_OR_DEPENDS |
1079 |
|
) { /* start an EDGE_OR_ list */ |
1080 |
number_of_alternatives = package_edge->version; |
number_of_alternatives = package_edge->version; |
1081 |
root_of_alternatives = package_edge; |
root_of_alternatives = package_edge; |
1082 |
continue; |
continue; |
1083 |
} else if (number_of_alternatives == 0) { /* not in the middle of an EDGE_OR_ list */ |
} |
1084 |
|
if (number_of_alternatives == 0) { /* not in the middle of an EDGE_OR_ list */ |
1085 |
number_of_alternatives = 1; |
number_of_alternatives = 1; |
1086 |
root_of_alternatives = NULL; |
root_of_alternatives = NULL; |
1087 |
} |
} |
1131 |
name_hashtable[package_node->name], |
name_hashtable[package_node->name], |
1132 |
package_edge->type == EDGE_PRE_DEPENDS ? "pre-" : "", |
package_edge->type == EDGE_PRE_DEPENDS ? "pre-" : "", |
1133 |
name_hashtable[root_of_alternatives->name]); |
name_hashtable[root_of_alternatives->name]); |
1134 |
else |
bb_error_msg_and_die( |
1135 |
bb_error_msg_and_die( |
"package %s %sdepends on %s, which %s\n", |
1136 |
"package %s %sdepends on %s, which %s\n", |
name_hashtable[package_node->name], |
1137 |
name_hashtable[package_node->name], |
package_edge->type == EDGE_PRE_DEPENDS ? "pre-" : "", |
1138 |
package_edge->type == EDGE_PRE_DEPENDS ? "pre-" : "", |
name_hashtable[package_edge->name], |
1139 |
name_hashtable[package_edge->name], |
describe_status(status_num)); |
1140 |
describe_status(status_num)); |
} |
1141 |
} else if (result == 0 && number_of_alternatives) { |
if (result == 0 && number_of_alternatives) { |
1142 |
/* we've found a package which |
/* we've found a package which |
1143 |
* satisfies the dependency, |
* satisfies the dependency, |
1144 |
* so skip over the rest of |
* so skip over the rest of |
1157 |
static char **create_list(const char *filename) |
static char **create_list(const char *filename) |
1158 |
{ |
{ |
1159 |
FILE *list_stream; |
FILE *list_stream; |
1160 |
char **file_list = NULL; |
char **file_list; |
1161 |
char *line = NULL; |
char *line; |
1162 |
int count = 0; |
int count; |
1163 |
|
|
1164 |
/* don't use [xw]fopen here, handle error ourself */ |
/* don't use [xw]fopen here, handle error ourself */ |
1165 |
list_stream = fopen(filename, "r"); |
list_stream = fopen_for_read(filename); |
1166 |
if (list_stream == NULL) { |
if (list_stream == NULL) { |
1167 |
return NULL; |
return NULL; |
1168 |
} |
} |
1169 |
|
|
1170 |
while ((line = xmalloc_getline(list_stream)) != NULL) { |
file_list = NULL; |
1171 |
file_list = xrealloc(file_list, sizeof(char *) * (count + 2)); |
count = 0; |
1172 |
file_list[count] = line; |
while ((line = xmalloc_fgetline(list_stream)) != NULL) { |
1173 |
count++; |
file_list = xrealloc_vector(file_list, 2, count); |
1174 |
|
file_list[count++] = line; |
1175 |
|
/*file_list[count] = NULL; - xrealloc_vector did it */ |
1176 |
} |
} |
1177 |
fclose(list_stream); |
fclose(list_stream); |
1178 |
|
|
1179 |
if (count == 0) { |
return file_list; |
|
return NULL; |
|
|
} else { |
|
|
file_list[count] = NULL; |
|
|
return file_list; |
|
|
} |
|
1180 |
} |
} |
1181 |
|
|
1182 |
/* maybe i should try and hook this into remove_file.c somehow */ |
/* maybe i should try and hook this into remove_file.c somehow */ |
1183 |
static int remove_file_array(char **remove_names, char **exclude_names) |
static int remove_file_array(char **remove_names, char **exclude_names) |
1184 |
{ |
{ |
1185 |
struct stat path_stat; |
struct stat path_stat; |
1186 |
int match_flag; |
int remove_flag = 1; /* not removed anything yet */ |
1187 |
int remove_flag = FALSE; |
int i, j; |
|
int i,j; |
|
1188 |
|
|
1189 |
if (remove_names == NULL) { |
if (remove_names == NULL) { |
1190 |
return FALSE; |
return 0; |
1191 |
} |
} |
1192 |
for (i = 0; remove_names[i] != NULL; i++) { |
for (i = 0; remove_names[i] != NULL; i++) { |
|
match_flag = FALSE; |
|
1193 |
if (exclude_names != NULL) { |
if (exclude_names != NULL) { |
1194 |
for (j = 0; exclude_names[j] != 0; j++) { |
for (j = 0; exclude_names[j] != NULL; j++) { |
1195 |
if (strcmp(remove_names[i], exclude_names[j]) == 0) { |
if (strcmp(remove_names[i], exclude_names[j]) == 0) { |
1196 |
match_flag = TRUE; |
goto skip; |
|
break; |
|
1197 |
} |
} |
1198 |
} |
} |
1199 |
} |
} |
1200 |
if (!match_flag) { |
/* TODO: why we are checking lstat? we can just try rm/rmdir */ |
1201 |
if (lstat(remove_names[i], &path_stat) < 0) { |
if (lstat(remove_names[i], &path_stat) < 0) { |
1202 |
continue; |
continue; |
1203 |
} |
} |
1204 |
if (S_ISDIR(path_stat.st_mode)) { |
if (S_ISDIR(path_stat.st_mode)) { |
1205 |
if (rmdir(remove_names[i]) != -1) { |
remove_flag &= rmdir(remove_names[i]); /* 0 if no error */ |
1206 |
remove_flag = TRUE; |
} else { |
1207 |
} |
remove_flag &= unlink(remove_names[i]); /* 0 if no error */ |
|
} else { |
|
|
if (unlink(remove_names[i]) != -1) { |
|
|
remove_flag = TRUE; |
|
|
} |
|
|
} |
|
1208 |
} |
} |
1209 |
|
skip: |
1210 |
|
continue; |
1211 |
} |
} |
1212 |
return remove_flag; |
return (remove_flag == 0); |
1213 |
} |
} |
1214 |
|
|
1215 |
static int run_package_script(const char *package_name, const char *script_type) |
static void run_package_script_or_die(const char *package_name, const char *script_type) |
1216 |
{ |
{ |
|
struct stat path_stat; |
|
1217 |
char *script_path; |
char *script_path; |
1218 |
int result; |
int result; |
1219 |
|
|
1220 |
script_path = xasprintf("/var/lib/dpkg/info/%s.%s", package_name, script_type); |
script_path = xasprintf("/var/lib/dpkg/info/%s.%s", package_name, script_type); |
1221 |
|
|
1222 |
/* If the file doesnt exist is isnt a fatal */ |
/* If the file doesnt exist is isnt fatal */ |
1223 |
result = lstat(script_path, &path_stat) < 0 ? EXIT_SUCCESS : system(script_path); |
result = access(script_path, F_OK) ? EXIT_SUCCESS : system(script_path); |
1224 |
free(script_path); |
free(script_path); |
1225 |
return result; |
if (result) |
1226 |
|
bb_error_msg_and_die("%s failed, exit code %d", script_type, result); |
1227 |
} |
} |
1228 |
|
|
1229 |
static const char *all_control_files[] = {"preinst", "postinst", "prerm", "postrm", |
/* |
1230 |
"list", "md5sums", "shlibs", "conffiles", "config", "templates", NULL }; |
The policy manual defines what scripts get called when and with |
1231 |
|
what arguments. I realize that busybox does not support all of |
1232 |
|
these scenarios, but it does support some of them; it does not, |
1233 |
|
however, run them with any parameters in run_package_script_or_die(). |
1234 |
|
Here are the scripts: |
1235 |
|
|
1236 |
|
preinst install |
1237 |
|
preinst install <old_version> |
1238 |
|
preinst upgrade <old_version> |
1239 |
|
preinst abort_upgrade <new_version> |
1240 |
|
postinst configure <most_recent_version> |
1241 |
|
postinst abort-upgade <new_version> |
1242 |
|
postinst abort-remove |
1243 |
|
postinst abort-remove in-favour <package> <version> |
1244 |
|
postinst abort-deconfigure in-favor <failed_install_package> removing <conflicting_package> <version> |
1245 |
|
prerm remove |
1246 |
|
prerm upgrade <new_version> |
1247 |
|
prerm failed-upgrade <old_version> |
1248 |
|
prerm remove in-favor <package> <new_version> |
1249 |
|
prerm deconfigure in-favour <package> <version> removing <package> <version> |
1250 |
|
postrm remove |
1251 |
|
postrm purge |
1252 |
|
postrm upgrade <new_version> |
1253 |
|
postrm failed-upgrade <old_version> |
1254 |
|
postrm abort-install |
1255 |
|
postrm abort-install <old_version> |
1256 |
|
postrm abort-upgrade <old_version> |
1257 |
|
postrm disappear <overwriter> <version> |
1258 |
|
*/ |
1259 |
|
static const char *const all_control_files[] = { |
1260 |
|
"preinst", "postinst", "prerm", "postrm", |
1261 |
|
"list", "md5sums", "shlibs", "conffiles", |
1262 |
|
"config", "templates" |
1263 |
|
}; |
1264 |
|
|
1265 |
static char **all_control_list(const char *package_name) |
static char **all_control_list(const char *package_name) |
1266 |
{ |
{ |
1268 |
char **remove_files; |
char **remove_files; |
1269 |
|
|
1270 |
/* Create a list of all /var/lib/dpkg/info/<package> files */ |
/* Create a list of all /var/lib/dpkg/info/<package> files */ |
1271 |
remove_files = xzalloc(sizeof(all_control_files)); |
remove_files = xzalloc(sizeof(all_control_files) + sizeof(char*)); |
1272 |
while (all_control_files[i]) { |
while (i < ARRAY_SIZE(all_control_files)) { |
1273 |
remove_files[i] = xasprintf("/var/lib/dpkg/info/%s.%s", package_name, all_control_files[i]); |
remove_files[i] = xasprintf("/var/lib/dpkg/info/%s.%s", |
1274 |
|
package_name, all_control_files[i]); |
1275 |
i++; |
i++; |
1276 |
} |
} |
1277 |
|
|
1280 |
|
|
1281 |
static void free_array(char **array) |
static void free_array(char **array) |
1282 |
{ |
{ |
|
|
|
1283 |
if (array) { |
if (array) { |
1284 |
unsigned i = 0; |
unsigned i = 0; |
1285 |
while (array[i]) { |
while (array[i]) { |
1294 |
* the status_hashtable to retrieve the info. This results in smaller code than |
* the status_hashtable to retrieve the info. This results in smaller code than |
1295 |
* scanning the status file. The resulting list, however, is unsorted. |
* scanning the status file. The resulting list, however, is unsorted. |
1296 |
*/ |
*/ |
1297 |
static void list_packages(void) |
static void list_packages(const char *pattern) |
1298 |
{ |
{ |
1299 |
int i; |
int i; |
1300 |
|
|
1302 |
puts("+++-==============-=============="); |
puts("+++-==============-=============="); |
1303 |
|
|
1304 |
/* go through status hash, dereference package hash and finally strings */ |
/* go through status hash, dereference package hash and finally strings */ |
1305 |
for (i=0; i<STATUS_HASH_PRIME+1; i++) { |
for (i = 0; i < STATUS_HASH_PRIME+1; i++) { |
|
|
|
1306 |
if (status_hashtable[i]) { |
if (status_hashtable[i]) { |
1307 |
const char *stat_str; /* status string */ |
const char *stat_str; /* status string */ |
1308 |
const char *name_str; /* package name */ |
const char *name_str; /* package name */ |
1315 |
name_str = name_hashtable[package_hashtable[status_hashtable[i]->package]->name]; |
name_str = name_hashtable[package_hashtable[status_hashtable[i]->package]->name]; |
1316 |
vers_str = name_hashtable[package_hashtable[status_hashtable[i]->package]->version]; |
vers_str = name_hashtable[package_hashtable[status_hashtable[i]->package]->version]; |
1317 |
|
|
1318 |
|
if (pattern && fnmatch(pattern, name_str, 0)) |
1319 |
|
continue; |
1320 |
|
|
1321 |
/* get abbreviation for status field 1 */ |
/* get abbreviation for status field 1 */ |
1322 |
s1 = stat_str[0] == 'i' ? 'i' : 'r'; |
s1 = stat_str[0] == 'i' ? 'i' : 'r'; |
1323 |
|
|
1324 |
/* get abbreviation for status field 2 */ |
/* get abbreviation for status field 2 */ |
1325 |
for (j=0, spccnt=0; stat_str[j] && spccnt<2; j++) { |
for (j = 0, spccnt = 0; stat_str[j] && spccnt < 2; j++) { |
1326 |
if (stat_str[j] == ' ') spccnt++; |
if (stat_str[j] == ' ') spccnt++; |
1327 |
} |
} |
1328 |
s2 = stat_str[j]; |
s2 = stat_str[j]; |
1330 |
/* print out the line formatted like Debian dpkg */ |
/* print out the line formatted like Debian dpkg */ |
1331 |
printf("%c%c %-14s %s\n", s1, s2, name_str, vers_str); |
printf("%c%c %-14s %s\n", s1, s2, name_str, vers_str); |
1332 |
} |
} |
1333 |
} |
} |
1334 |
} |
} |
1335 |
|
|
1336 |
static void remove_package(const unsigned package_num, int noisy) |
static void remove_package(const unsigned package_num, int noisy) |
1343 |
char **exclude_files; |
char **exclude_files; |
1344 |
char list_name[package_name_length + 25]; |
char list_name[package_name_length + 25]; |
1345 |
char conffile_name[package_name_length + 30]; |
char conffile_name[package_name_length + 30]; |
|
int return_value; |
|
1346 |
|
|
1347 |
if (noisy) |
if (noisy) |
1348 |
printf("Removing %s (%s)...\n", package_name, package_version); |
printf("Removing %s (%s)...\n", package_name, package_version); |
1349 |
|
|
1350 |
/* run prerm script */ |
/* Run prerm script */ |
1351 |
return_value = run_package_script(package_name, "prerm"); |
run_package_script_or_die(package_name, "prerm"); |
|
if (return_value == -1) { |
|
|
bb_error_msg_and_die("script failed, prerm failure"); |
|
|
} |
|
1352 |
|
|
1353 |
/* Create a list of files to remove, and a separate list of those to keep */ |
/* Create a list of files to remove, and a separate list of those to keep */ |
1354 |
sprintf(list_name, "/var/lib/dpkg/info/%s.list", package_name); |
sprintf(list_name, "/var/lib/dpkg/info/%s.%s", package_name, "list"); |
1355 |
remove_files = create_list(list_name); |
remove_files = create_list(list_name); |
1356 |
|
|
1357 |
sprintf(conffile_name, "/var/lib/dpkg/info/%s.conffiles", package_name); |
sprintf(conffile_name, "/var/lib/dpkg/info/%s.%s", package_name, "conffiles"); |
1358 |
exclude_files = create_list(conffile_name); |
exclude_files = create_list(conffile_name); |
1359 |
|
|
1360 |
/* Some directories can't be removed straight away, so do multiple passes */ |
/* Some directories can't be removed straight away, so do multiple passes */ |
1361 |
while (remove_file_array(remove_files, exclude_files)) /*repeat */; |
while (remove_file_array(remove_files, exclude_files)) |
1362 |
|
continue; |
1363 |
free_array(exclude_files); |
free_array(exclude_files); |
1364 |
free_array(remove_files); |
free_array(remove_files); |
1365 |
|
|
1366 |
/* Create a list of files in /var/lib/dpkg/info/<package>.* to keep */ |
/* Create a list of files in /var/lib/dpkg/info/<package>.* to keep */ |
1367 |
exclude_files = xzalloc(sizeof(char*) * 3); |
exclude_files = xzalloc(sizeof(char*) * 3); |
1368 |
exclude_files[0] = xstrdup(conffile_name); |
exclude_files[0] = xstrdup(conffile_name); |
1369 |
exclude_files[1] = xasprintf("/var/lib/dpkg/info/%s.postrm", package_name); |
exclude_files[1] = xasprintf("/var/lib/dpkg/info/%s.%s", package_name, "postrm"); |
1370 |
|
|
1371 |
/* Create a list of all /var/lib/dpkg/info/<package> files */ |
/* Create a list of all /var/lib/dpkg/info/<package> files */ |
1372 |
remove_files = all_control_list(package_name); |
remove_files = all_control_list(package_name); |
1375 |
free_array(remove_files); |
free_array(remove_files); |
1376 |
free_array(exclude_files); |
free_array(exclude_files); |
1377 |
|
|
1378 |
/* rename <package>.conffile to <package>.list */ |
/* rename <package>.conffiles to <package>.list |
1379 |
|
* The conffiles control file isn't required in Debian packages, so don't |
1380 |
|
* error out if it's missing. */ |
1381 |
rename(conffile_name, list_name); |
rename(conffile_name, list_name); |
1382 |
|
|
1383 |
/* Change package status */ |
/* Change package status */ |
1395 |
|
|
1396 |
printf("Purging %s (%s)...\n", package_name, package_version); |
printf("Purging %s (%s)...\n", package_name, package_version); |
1397 |
|
|
1398 |
/* run prerm script */ |
/* Run prerm script */ |
1399 |
if (run_package_script(package_name, "prerm") != 0) { |
run_package_script_or_die(package_name, "prerm"); |
|
bb_error_msg_and_die("script failed, prerm failure"); |
|
|
} |
|
1400 |
|
|
1401 |
/* Create a list of files to remove */ |
/* Create a list of files to remove */ |
1402 |
sprintf(list_name, "/var/lib/dpkg/info/%s.list", package_name); |
sprintf(list_name, "/var/lib/dpkg/info/%s.%s", package_name, "list"); |
1403 |
remove_files = create_list(list_name); |
remove_files = create_list(list_name); |
1404 |
|
|
1405 |
exclude_files = xzalloc(sizeof(char*)); |
exclude_files = xzalloc(sizeof(char*)); |
1414 |
free_array(remove_files); |
free_array(remove_files); |
1415 |
free(exclude_files); |
free(exclude_files); |
1416 |
|
|
1417 |
/* run postrm script */ |
/* Run postrm script */ |
1418 |
if (run_package_script(package_name, "postrm") == -1) { |
run_package_script_or_die(package_name, "postrm"); |
|
bb_error_msg_and_die("postrm fialure.. set status to what?"); |
|
|
} |
|
1419 |
|
|
1420 |
/* Change package status */ |
/* Change package status */ |
1421 |
set_status(status_num, "not-installed", 3); |
set_status(status_num, "not-installed", 3); |
1442 |
tar_handle->src_fd = ar_handle->src_fd; |
tar_handle->src_fd = ar_handle->src_fd; |
1443 |
|
|
1444 |
/* We don't care about data.tar.* or debian-binary, just control.tar.* */ |
/* We don't care about data.tar.* or debian-binary, just control.tar.* */ |
1445 |
#ifdef CONFIG_FEATURE_DEB_TAR_GZ |
#if ENABLE_FEATURE_SEAMLESS_GZ |
1446 |
llist_add_to(&(ar_handle->accept), "control.tar.gz"); |
llist_add_to(&(ar_handle->accept), (char*)"control.tar.gz"); |
1447 |
#endif |
#endif |
1448 |
#ifdef CONFIG_FEATURE_DEB_TAR_BZ2 |
#if ENABLE_FEATURE_SEAMLESS_BZ2 |
1449 |
llist_add_to(&(ar_handle->accept), "control.tar.bz2"); |
llist_add_to(&(ar_handle->accept), (char*)"control.tar.bz2"); |
1450 |
#endif |
#endif |
1451 |
|
|
1452 |
/* Assign the tar handle as a subarchive of the ar handle */ |
/* Assign the tar handle as a subarchive of the ar handle */ |
1453 |
ar_handle->sub_archive = tar_handle; |
ar_handle->sub_archive = tar_handle; |
|
|
|
|
return; |
|
1454 |
} |
} |
1455 |
|
|
1456 |
static void init_archive_deb_data(archive_handle_t *ar_handle) |
static void init_archive_deb_data(archive_handle_t *ar_handle) |
1462 |
tar_handle->src_fd = ar_handle->src_fd; |
tar_handle->src_fd = ar_handle->src_fd; |
1463 |
|
|
1464 |
/* We don't care about control.tar.* or debian-binary, just data.tar.* */ |
/* We don't care about control.tar.* or debian-binary, just data.tar.* */ |
1465 |
#ifdef CONFIG_FEATURE_DEB_TAR_GZ |
#if ENABLE_FEATURE_SEAMLESS_GZ |
1466 |
llist_add_to(&(ar_handle->accept), "data.tar.gz"); |
llist_add_to(&(ar_handle->accept), (char*)"data.tar.gz"); |
1467 |
#endif |
#endif |
1468 |
#ifdef CONFIG_FEATURE_DEB_TAR_BZ2 |
#if ENABLE_FEATURE_SEAMLESS_BZ2 |
1469 |
llist_add_to(&(ar_handle->accept), "data.tar.bz2"); |
llist_add_to(&(ar_handle->accept), (char*)"data.tar.bz2"); |
1470 |
#endif |
#endif |
1471 |
|
|
1472 |
/* Assign the tar handle as a subarchive of the ar handle */ |
/* Assign the tar handle as a subarchive of the ar handle */ |
1473 |
ar_handle->sub_archive = tar_handle; |
ar_handle->sub_archive = tar_handle; |
|
|
|
|
return; |
|
1474 |
} |
} |
1475 |
|
|
1476 |
static char *deb_extract_control_file_to_buffer(archive_handle_t *ar_handle, llist_t *myaccept) |
static char *deb_extract_control_file_to_buffer(archive_handle_t *ar_handle, llist_t *myaccept) |
1485 |
return ar_handle->sub_archive->buffer; |
return ar_handle->sub_archive->buffer; |
1486 |
} |
} |
1487 |
|
|
1488 |
static void data_extract_all_prefix(archive_handle_t *archive_handle) |
static void FAST_FUNC data_extract_all_prefix(archive_handle_t *archive_handle) |
1489 |
{ |
{ |
1490 |
char *name_ptr = archive_handle->file_header->name; |
char *name_ptr = archive_handle->file_header->name; |
1491 |
|
|
1494 |
archive_handle->file_header->name = xasprintf("%s%s", archive_handle->buffer, name_ptr); |
archive_handle->file_header->name = xasprintf("%s%s", archive_handle->buffer, name_ptr); |
1495 |
data_extract_all(archive_handle); |
data_extract_all(archive_handle); |
1496 |
} |
} |
|
return; |
|
1497 |
} |
} |
1498 |
|
|
1499 |
static void unpack_package(deb_file_t *deb_file) |
static void unpack_package(deb_file_t *deb_file) |
1505 |
char *list_filename; |
char *list_filename; |
1506 |
archive_handle_t *archive_handle; |
archive_handle_t *archive_handle; |
1507 |
FILE *out_stream; |
FILE *out_stream; |
1508 |
llist_t *accept_list = NULL; |
llist_t *accept_list; |
1509 |
int i = 0; |
int i; |
1510 |
|
|
1511 |
/* If existing version, remove it first */ |
/* If existing version, remove it first */ |
1512 |
if (strcmp(name_hashtable[get_status(status_num, 3)], "installed") == 0) { |
if (strcmp(name_hashtable[get_status(status_num, 3)], "installed") == 0) { |
1520 |
} |
} |
1521 |
|
|
1522 |
/* Extract control.tar.gz to /var/lib/dpkg/info/<package>.filename */ |
/* Extract control.tar.gz to /var/lib/dpkg/info/<package>.filename */ |
1523 |
info_prefix = xasprintf("/var/lib/dpkg/info/%s.", package_name); |
info_prefix = xasprintf("/var/lib/dpkg/info/%s.%s", package_name, ""); |
1524 |
archive_handle = init_archive_deb_ar(deb_file->filename); |
archive_handle = init_archive_deb_ar(deb_file->filename); |
1525 |
init_archive_deb_control(archive_handle); |
init_archive_deb_control(archive_handle); |
1526 |
|
|
1527 |
while (all_control_files[i]) { |
accept_list = NULL; |
1528 |
|
i = 0; |
1529 |
|
while (i < ARRAY_SIZE(all_control_files)) { |
1530 |
char *c = xasprintf("./%s", all_control_files[i]); |
char *c = xasprintf("./%s", all_control_files[i]); |
1531 |
llist_add_to(&accept_list, c); |
llist_add_to(&accept_list, c); |
1532 |
i++; |
i++; |
1535 |
archive_handle->sub_archive->filter = filter_accept_list; |
archive_handle->sub_archive->filter = filter_accept_list; |
1536 |
archive_handle->sub_archive->action_data = data_extract_all_prefix; |
archive_handle->sub_archive->action_data = data_extract_all_prefix; |
1537 |
archive_handle->sub_archive->buffer = info_prefix; |
archive_handle->sub_archive->buffer = info_prefix; |
1538 |
archive_handle->sub_archive->flags |= ARCHIVE_EXTRACT_UNCONDITIONAL; |
archive_handle->sub_archive->ah_flags |= ARCHIVE_EXTRACT_UNCONDITIONAL; |
1539 |
unpack_ar_archive(archive_handle); |
unpack_ar_archive(archive_handle); |
1540 |
|
|
1541 |
/* Run the preinst prior to extracting */ |
/* Run the preinst prior to extracting */ |
1542 |
if (run_package_script(package_name, "preinst") != 0) { |
run_package_script_or_die(package_name, "preinst"); |
|
/* when preinst returns exit code != 0 then quit installation process */ |
|
|
bb_error_msg_and_die("subprocess pre-installation script returned error"); |
|
|
} |
|
1543 |
|
|
1544 |
/* Extract data.tar.gz to the root directory */ |
/* Extract data.tar.gz to the root directory */ |
1545 |
archive_handle = init_archive_deb_ar(deb_file->filename); |
archive_handle = init_archive_deb_ar(deb_file->filename); |
1546 |
init_archive_deb_data(archive_handle); |
init_archive_deb_data(archive_handle); |
1547 |
archive_handle->sub_archive->action_data = data_extract_all_prefix; |
archive_handle->sub_archive->action_data = data_extract_all_prefix; |
1548 |
archive_handle->sub_archive->buffer = "/"; |
archive_handle->sub_archive->buffer = (char*)"/"; /* huh? */ |
1549 |
archive_handle->sub_archive->flags |= ARCHIVE_EXTRACT_UNCONDITIONAL; |
archive_handle->sub_archive->ah_flags |= ARCHIVE_EXTRACT_UNCONDITIONAL; |
1550 |
unpack_ar_archive(archive_handle); |
unpack_ar_archive(archive_handle); |
1551 |
|
|
1552 |
/* Create the list file */ |
/* Create the list file */ |
1553 |
list_filename = xasprintf("/var/lib/dpkg/info/%s.list", package_name); |
list_filename = xasprintf("/var/lib/dpkg/info/%s.%s", package_name, "list"); |
1554 |
out_stream = xfopen(list_filename, "w"); |
out_stream = xfopen_for_write(list_filename); |
1555 |
while (archive_handle->sub_archive->passed) { |
while (archive_handle->sub_archive->passed) { |
1556 |
/* the leading . has been stripped by data_extract_all_prefix already */ |
/* the leading . has been stripped by data_extract_all_prefix already */ |
1557 |
fputs(archive_handle->sub_archive->passed->data, out_stream); |
fputs(archive_handle->sub_archive->passed->data, out_stream); |
1577 |
printf("Setting up %s (%s)...\n", package_name, package_version); |
printf("Setting up %s (%s)...\n", package_name, package_version); |
1578 |
|
|
1579 |
/* Run the postinst script */ |
/* Run the postinst script */ |
1580 |
if (run_package_script(package_name, "postinst") != 0) { |
/* TODO: handle failure gracefully */ |
1581 |
/* TODO: handle failure gracefully */ |
run_package_script_or_die(package_name, "postinst"); |
1582 |
bb_error_msg_and_die("postrm failure.. set status to what?"); |
|
|
} |
|
1583 |
/* Change status to reflect success */ |
/* Change status to reflect success */ |
1584 |
set_status(status_num, "install", 1); |
set_status(status_num, "install", 1); |
1585 |
set_status(status_num, "installed", 3); |
set_status(status_num, "installed", 3); |
1586 |
} |
} |
1587 |
|
|
1588 |
int dpkg_main(int argc, char **argv) |
int dpkg_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
1589 |
|
int dpkg_main(int argc UNUSED_PARAM, char **argv) |
1590 |
{ |
{ |
1591 |
deb_file_t **deb_file = NULL; |
deb_file_t **deb_file = NULL; |
1592 |
status_node_t *status_node; |
status_node_t *status_node; |
1605 |
OPT_purge = 0x10, |
OPT_purge = 0x10, |
1606 |
OPT_remove = 0x20, |
OPT_remove = 0x20, |
1607 |
OPT_unpack = 0x40, |
OPT_unpack = 0x40, |
|
REQ_package_name = 0x8000, |
|
|
REQ_filename = 0x4000, |
|
1608 |
}; |
}; |
1609 |
|
|
1610 |
opt = getopt32(argc, argv, "CF:ilPru", &str_f); |
INIT_G(); |
1611 |
if (opt & OPT_configure) opt |= REQ_package_name; // -C |
|
1612 |
|
opt = getopt32(argv, "CF:ilPru", &str_f); |
1613 |
|
//if (opt & OPT_configure) ... // -C |
1614 |
if (opt & OPT_force_ignore_depends) { // -F (--force in official dpkg) |
if (opt & OPT_force_ignore_depends) { // -F (--force in official dpkg) |
1615 |
if (strcmp(str_f, "depends")) |
if (strcmp(str_f, "depends")) |
1616 |
opt &= ~OPT_force_ignore_depends; |
opt &= ~OPT_force_ignore_depends; |
1617 |
} |
} |
1618 |
if (opt & OPT_install) opt |= REQ_filename; // -i |
//if (opt & OPT_install) ... // -i |
1619 |
//if (opt & OPT_list_installed) ... // -l |
//if (opt & OPT_list_installed) ... // -l |
1620 |
if (opt & OPT_purge) opt |= REQ_package_name; // -P |
//if (opt & OPT_purge) ... // -P |
1621 |
if (opt & OPT_remove) opt |= REQ_package_name; // -r |
//if (opt & OPT_remove) ... // -r |
1622 |
if (opt & OPT_unpack) opt |= REQ_filename; // -u (--unpack in official dpkg) |
//if (opt & OPT_unpack) ... // -u (--unpack in official dpkg) |
|
argc -= optind; |
|
1623 |
argv += optind; |
argv += optind; |
1624 |
/* check for non-option argument if expected */ |
/* check for non-option argument if expected */ |
1625 |
if (!opt || (!argc && !(opt && OPT_list_installed))) |
if (!opt || (!argv[0] && !(opt && OPT_list_installed))) |
1626 |
bb_show_usage(); |
bb_show_usage(); |
1627 |
|
|
|
name_hashtable = xzalloc(sizeof(name_hashtable[0]) * (NAME_HASH_PRIME + 1)); |
|
|
package_hashtable = xzalloc(sizeof(package_hashtable[0]) * (PACKAGE_HASH_PRIME + 1)); |
|
|
status_hashtable = xzalloc(sizeof(status_hashtable[0]) * (STATUS_HASH_PRIME + 1)); |
|
|
|
|
1628 |
/* puts("(Reading database ... xxxxx files and directories installed.)"); */ |
/* puts("(Reading database ... xxxxx files and directories installed.)"); */ |
1629 |
index_status_file("/var/lib/dpkg/status"); |
index_status_file("/var/lib/dpkg/status"); |
1630 |
|
|
1631 |
/* if the list action was given print the installed packages and exit */ |
/* if the list action was given print the installed packages and exit */ |
1632 |
if (opt & OPT_list_installed) { |
if (opt & OPT_list_installed) { |
1633 |
list_packages(); |
list_packages(argv[0]); |
1634 |
return EXIT_SUCCESS; |
return EXIT_SUCCESS; |
1635 |
} |
} |
1636 |
|
|
1637 |
/* Read arguments and store relevant info in structs */ |
/* Read arguments and store relevant info in structs */ |
1638 |
while (*argv) { |
while (*argv) { |
1639 |
/* deb_count = nb_elem - 1 and we need nb_elem + 1 to allocate terminal node [NULL pointer] */ |
/* deb_count = nb_elem - 1 and we need nb_elem + 1 to allocate terminal node [NULL pointer] */ |
1640 |
deb_file = xrealloc(deb_file, sizeof(deb_file_t *) * (deb_count + 2)); |
deb_file = xrealloc_vector(deb_file, 2, deb_count); |
1641 |
deb_file[deb_count] = xzalloc(sizeof(deb_file_t)); |
deb_file[deb_count] = xzalloc(sizeof(deb_file[0][0])); |
1642 |
if (opt & REQ_filename) { |
if (opt & (OPT_install | OPT_unpack)) { |
1643 |
|
/* -i/-u: require filename */ |
1644 |
archive_handle_t *archive_handle; |
archive_handle_t *archive_handle; |
1645 |
llist_t *control_list = NULL; |
llist_t *control_list = NULL; |
1646 |
|
|
1647 |
/* Extract the control file */ |
/* Extract the control file */ |
1648 |
llist_add_to(&control_list, "./control"); |
llist_add_to(&control_list, (char*)"./control"); |
1649 |
archive_handle = init_archive_deb_ar(argv[0]); |
archive_handle = init_archive_deb_ar(argv[0]); |
1650 |
init_archive_deb_control(archive_handle); |
init_archive_deb_control(archive_handle); |
1651 |
deb_file[deb_count]->control_file = deb_extract_control_file_to_buffer(archive_handle, control_list); |
deb_file[deb_count]->control_file = deb_extract_control_file_to_buffer(archive_handle, control_list); |
1663 |
deb_file[deb_count]->package = (unsigned) package_num; |
deb_file[deb_count]->package = (unsigned) package_num; |
1664 |
|
|
1665 |
/* Add the package to the status hashtable */ |
/* Add the package to the status hashtable */ |
1666 |
if (opt & (OPT_unpack|OPT_install)) { |
if (opt & (OPT_unpack | OPT_install)) { |
1667 |
/* Try and find a currently installed version of this package */ |
/* Try and find a currently installed version of this package */ |
1668 |
status_num = search_status_hashtable(name_hashtable[package_hashtable[deb_file[deb_count]->package]->name]); |
status_num = search_status_hashtable(name_hashtable[package_hashtable[deb_file[deb_count]->package]->name]); |
1669 |
/* If no previous entry was found initialise a new entry */ |
/* If no previous entry was found initialise a new entry */ |
1681 |
set_status(status_num, "reinstreq", 2); |
set_status(status_num, "reinstreq", 2); |
1682 |
} |
} |
1683 |
} |
} |
1684 |
} |
} else if (opt & (OPT_configure | OPT_purge | OPT_remove)) { |
1685 |
else if (opt & REQ_package_name) { |
/* -C/-p/-r: require package name */ |
1686 |
deb_file[deb_count]->package = search_package_hashtable( |
deb_file[deb_count]->package = search_package_hashtable( |
1687 |
search_name_hashtable(argv[0]), |
search_name_hashtable(argv[0]), |
1688 |
search_name_hashtable("ANY"), VER_ANY); |
search_name_hashtable("ANY"), VER_ANY); |
1701 |
bb_error_msg_and_die("%s is already removed", name_hashtable[package_hashtable[package_num]->name]); |
bb_error_msg_and_die("%s is already removed", name_hashtable[package_hashtable[package_num]->name]); |
1702 |
} |
} |
1703 |
set_status(status_num, "deinstall", 1); |
set_status(status_num, "deinstall", 1); |
1704 |
} |
} else if (opt & OPT_purge) { |
|
else if (opt & OPT_purge) { |
|
1705 |
/* if package status is "conf-files" then its ok */ |
/* if package status is "conf-files" then its ok */ |
1706 |
if (strcmp(name_hashtable[state_status], "not-installed") == 0) { |
if (strcmp(name_hashtable[state_status], "not-installed") == 0) { |
1707 |
bb_error_msg_and_die("%s is already purged", name_hashtable[package_hashtable[package_num]->name]); |
bb_error_msg_and_die("%s is already purged", name_hashtable[package_hashtable[package_num]->name]); |
1712 |
deb_count++; |
deb_count++; |
1713 |
argv++; |
argv++; |
1714 |
} |
} |
1715 |
|
if (!deb_count) |
1716 |
|
bb_error_msg_and_die("no package files specified"); |
1717 |
deb_file[deb_count] = NULL; |
deb_file[deb_count] = NULL; |
1718 |
|
|
1719 |
/* Check that the deb file arguments are installable */ |
/* Check that the deb file arguments are installable */ |
1720 |
if (!(opt & OPT_force_ignore_depends)) { |
if (!(opt & OPT_force_ignore_depends)) { |
1721 |
if (!check_deps(deb_file, 0, deb_count)) { |
if (!check_deps(deb_file, 0 /*, deb_count*/)) { |
1722 |
bb_error_msg_and_die("dependency check failed"); |
bb_error_msg_and_die("dependency check failed"); |
1723 |
} |
} |
1724 |
} |
} |
1765 |
} |
} |
1766 |
|
|
1767 |
for (i = 0; i < PACKAGE_HASH_PRIME; i++) { |
for (i = 0; i < PACKAGE_HASH_PRIME; i++) { |
1768 |
if (package_hashtable[i] != NULL) { |
free_package(package_hashtable[i]); |
|
free_package(package_hashtable[i]); |
|
|
} |
|
1769 |
} |
} |
1770 |
|
|
1771 |
for (i = 0; i < STATUS_HASH_PRIME; i++) { |
for (i = 0; i < STATUS_HASH_PRIME; i++) { |