Changeset 2725 in MondoRescue for branches/2.2.9/mindi-busybox/archival/dpkg.c
- Timestamp:
- Feb 25, 2011, 9:26:54 PM (13 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
branches/2.2.9/mindi-busybox/archival/dpkg.c
r1765 r2725 7 7 * copyright (c) 2001 by glenn mcgrath 8 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 * 9 13 * started life as a busybox implementation of udpkg 10 14 * 11 * licensed under gplv2 or later, see file license in this tarball for details.15 * Licensed under GPLv2 or later, see file LICENSE in this source tree. 12 16 */ 13 17 … … 26 30 27 31 #include "libbb.h" 28 #include "unarchive.h" 32 #include <fnmatch.h> 33 #include "archive.h" 29 34 30 35 /* note: if you vary hash_prime sizes be aware, … … 76 81 } status_node_t; 77 82 78 /* Were statically declared here, but such a big bss is nommu-unfriendly */ 79 static char **name_hashtable; /* [NAME_HASH_PRIME + 1] */ 80 static common_node_t **package_hashtable; /* [PACKAGE_HASH_PRIME + 1] */ 81 static status_node_t **status_hashtable; /* [STATUS_HASH_PRIME + 1] */ 83 84 /* Globals */ 85 struct 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 82 98 83 99 /* Even numbers are for 'extras', like ored dependencies or null */ … … 124 140 * shift amount is mod 24 because long int is 32 bit and data 125 141 * to be shifted is 8, don't want to shift data to where it has 126 * no effect */127 hash_num += ( (key[i] + key[i-1]) << ((key[i] * i) % 24));142 * no effect */ 143 hash_num += (key[i] + key[i-1]) << ((key[i] * i) % 24); 128 144 } 129 145 *start = (unsigned) hash_num % hash_prime; … … 134 150 static int search_name_hashtable(const char *key) 135 151 { 136 unsigned probe_address = 0;137 unsigned probe_decrement = 0;152 unsigned probe_address; 153 unsigned probe_decrement; 138 154 139 155 make_hash(key, &probe_address, &probe_decrement, NAME_HASH_PRIME); … … 156 172 static unsigned search_status_hashtable(const char *key) 157 173 { 158 unsigned probe_address = 0;159 unsigned probe_decrement = 0;174 unsigned probe_address; 175 unsigned probe_decrement; 160 176 161 177 make_hash(key, &probe_address, &probe_decrement, STATUS_HASH_PRIME); … … 172 188 } 173 189 174 /* Need to rethink version comparison, maybe the official dpkg has something i can use ? */ 175 static int version_compare_part(const char *version1, const char *version2) 176 { 177 int upstream_len1 = 0; 178 int upstream_len2 = 0; 179 char *name1_char; 180 char *name2_char; 181 int len1 = 0; 182 int len2 = 0; 183 int tmp_int; 184 int ver_num1; 185 int ver_num2; 186 187 if (version1 == NULL) { 188 version1 = xstrdup(""); 189 } 190 if (version2 == NULL) { 191 version2 = xstrdup(""); 192 } 193 upstream_len1 = strlen(version1); 194 upstream_len2 = strlen(version2); 195 196 while ((len1 < upstream_len1) || (len2 < upstream_len2)) { 197 /* Compare non-digit section */ 198 tmp_int = strcspn(&version1[len1], "0123456789"); 199 name1_char = xstrndup(&version1[len1], tmp_int); 200 len1 += tmp_int; 201 tmp_int = strcspn(&version2[len2], "0123456789"); 202 name2_char = xstrndup(&version2[len2], tmp_int); 203 len2 += tmp_int; 204 tmp_int = strcmp(name1_char, name2_char); 205 free(name1_char); 206 free(name2_char); 207 if (tmp_int != 0) { 208 return tmp_int; 209 } 210 211 /* Compare digits */ 212 tmp_int = strspn(&version1[len1], "0123456789"); 213 name1_char = xstrndup(&version1[len1], tmp_int); 214 len1 += tmp_int; 215 tmp_int = strspn(&version2[len2], "0123456789"); 216 name2_char = xstrndup(&version2[len2], tmp_int); 217 len2 += tmp_int; 218 ver_num1 = atoi(name1_char); 219 ver_num2 = atoi(name2_char); 220 free(name1_char); 221 free(name2_char); 222 if (ver_num1 < ver_num2) { 190 static 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 */ 201 static 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)) 223 233 return -1; 224 } 225 if (ver_num1 > ver_num2) { 226 return 1; 227 } 234 if (first_diff) 235 return first_diff; 228 236 } 229 237 return 0; … … 238 246 char *ch_ver1 = name_hashtable[ver1]; 239 247 char *ch_ver2 = name_hashtable[ver2]; 240 241 char epoch1, epoch2;248 unsigned epoch1 = 0, epoch2 = 0; 249 char *colon; 242 250 char *deb_ver1, *deb_ver2; 243 char *ver1_ptr, *ver2_ptr;244 251 char *upstream_ver1; 245 252 char *upstream_ver2; … … 247 254 248 255 /* Compare epoch */ 249 if (ch_ver1[1] == ':') { 250 epoch1 = ch_ver1[0]; 251 ver1_ptr = strchr(ch_ver1, ':') + 1; 252 } else { 253 epoch1 = '0'; 254 ver1_ptr = ch_ver1; 255 } 256 if (ch_ver2[1] == ':') { 257 epoch2 = ch_ver2[0]; 258 ver2_ptr = strchr(ch_ver2, ':') + 1; 259 } else { 260 epoch2 = '0'; 261 ver2_ptr = ch_ver2; 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; 262 265 } 263 266 if (epoch1 < epoch2) { 264 267 return -1; 265 268 } 266 elseif (epoch1 > epoch2) {269 if (epoch1 > epoch2) { 267 270 return 1; 268 271 } 269 272 270 273 /* Compare upstream version */ 271 upstream_ver1 = xstrdup( ver1_ptr);272 upstream_ver2 = xstrdup( ver2_ptr);274 upstream_ver1 = xstrdup(ch_ver1); 275 upstream_ver2 = xstrdup(ch_ver2); 273 276 274 277 /* Chop off debian version, and store for later use */ … … 276 279 deb_ver2 = strrchr(upstream_ver2, '-'); 277 280 if (deb_ver1) { 278 deb_ver1[0] = '\0'; 279 deb_ver1++; 281 *deb_ver1++ = '\0'; 280 282 } 281 283 if (deb_ver2) { 282 deb_ver2[0] = '\0'; 283 deb_ver2++; 284 *deb_ver2++ = '\0'; 284 285 } 285 286 result = version_compare_part(upstream_ver1, upstream_ver2); 286 if ( !result)287 if (result == 0) { 287 288 /* Compare debian versions */ 288 289 result = version_compare_part(deb_ver1, deb_ver2); 290 } 289 291 290 292 free(upstream_ver1); … … 313 315 } 314 316 315 316 317 static int search_package_hashtable(const unsigned name, const unsigned version, const unsigned operator) 317 318 { 318 unsigned probe_address = 0;319 unsigned probe_decrement = 0;319 unsigned probe_address; 320 unsigned probe_decrement; 320 321 321 322 make_hash(name_hashtable[name], &probe_address, &probe_decrement, PACKAGE_HASH_PRIME); … … 373 374 static void add_edge_to_node(common_node_t *node, edge_t *edge) 374 375 { 375 node->num_of_edges++; 376 node->edge = xrealloc(node->edge, sizeof(edge_t) * (node->num_of_edges + 1)); 377 node->edge[node->num_of_edges - 1] = edge; 376 node->edge = xrealloc_vector(node->edge, 2, node->num_of_edges); 377 node->edge[node->num_of_edges++] = edge; 378 378 } 379 379 … … 411 411 && (strcmp(field, field2) != 0) 412 412 ) { 413 or_edge = x malloc(sizeof(edge_t));413 or_edge = xzalloc(sizeof(edge_t)); 414 414 or_edge->type = edge_type + 1; 415 415 or_edge->name = search_name_hashtable(field); 416 or_edge->version = 0; // tracks the number of alternatives416 //or_edge->version = 0; // tracks the number of alternatives 417 417 add_edge_to_node(parent_node, or_edge); 418 418 } … … 440 440 if (strncmp(version, "=", offset_ch) == 0) { 441 441 edge->operator = VER_EQUAL; 442 } 443 else if (strncmp(version, "<<", offset_ch) == 0) { 442 } else if (strncmp(version, "<<", offset_ch) == 0) { 444 443 edge->operator = VER_LESS; 445 } 446 else if (strncmp(version, "<=", offset_ch) == 0) { 444 } else if (strncmp(version, "<=", offset_ch) == 0) { 447 445 edge->operator = VER_LESS_EQUAL; 448 } 449 else if (strncmp(version, ">>", offset_ch) == 0) { 446 } else if (strncmp(version, ">>", offset_ch) == 0) { 450 447 edge->operator = VER_MORE; 451 } 452 else if (strncmp(version, ">=", offset_ch) == 0) { 448 } else if (strncmp(version, ">=", offset_ch) == 0) { 453 449 edge->operator = VER_MORE_EQUAL; 454 450 } else { … … 497 493 498 494 /* 499 * Gets the next package field from package_buffer, sep erated into the field name495 * Gets the next package field from package_buffer, separated into the field name 500 496 * and field value, it returns the int offset to the first character of the next field 501 497 */ … … 603 599 604 600 if (field_name == NULL) { 605 goto fill_package_struct_cleanup; /* Oh no, the dreaded goto statement! */601 goto fill_package_struct_cleanup; 606 602 } 607 603 … … 736 732 } 737 733 738 739 734 static void index_status_file(const char *filename) 740 735 { … … 745 740 unsigned status_num; 746 741 747 status_file = xfopen (filename, "r");748 while ((control_buffer = xmalloc_fget s_str(status_file, "\n\n")) != NULL) {742 status_file = xfopen_for_read(filename); 743 while ((control_buffer = xmalloc_fgetline_str(status_file, "\n\n")) != NULL) { 749 744 const unsigned package_num = fill_package_struct(control_buffer); 750 745 if (package_num != -1) { … … 787 782 static void write_status_file(deb_file_t **deb_file) 788 783 { 789 FILE *old_status_file = xfopen ("/var/lib/dpkg/status", "r");790 FILE *new_status_file = xfopen ("/var/lib/dpkg/status.udeb", "w");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"); 791 786 char *package_name; 792 787 char *status_from_file; … … 799 794 800 795 /* Update previously known packages */ 801 while ((control_buffer = xmalloc_fget s_str(old_status_file, "\n\n")) != NULL) {796 while ((control_buffer = xmalloc_fgetline_str(old_status_file, "\n\n")) != NULL) { 802 797 tmp_string = strstr(control_buffer, "Package:"); 803 798 if (tmp_string == NULL) { … … 811 806 tmp_string = strstr(control_buffer, "Status:"); 812 807 if (tmp_string != NULL) { 813 /* Sep erate the status value from the control buffer */808 /* Separate the status value from the control buffer */ 814 809 tmp_string += 7; 815 810 tmp_string += strspn(tmp_string, " \n\t"); … … 863 858 break; 864 859 } 865 if ((strcmp(field_name, "Priority") == 0) || 866 (strcmp(field_name, "Section") == 0)) { 860 if ((strcmp(field_name, "Priority") == 0) 861 || (strcmp(field_name, "Section") == 0) 862 ) { 867 863 fprintf(new_status_file, "%s: %s\n", field_name, field_value); 868 864 } … … 871 867 fputs("\n", new_status_file); 872 868 } 873 else if 869 else if (strcmp("config-files", name_hashtable[state_status]) == 0) { 874 870 /* only change the status line */ 875 871 while (1) { … … 914 910 fclose(new_status_file); 915 911 916 917 912 /* Create a separate backfile to dpkg */ 918 913 if (rename("/var/lib/dpkg/status", "/var/lib/dpkg/status.udeb.bak") == -1) { 919 struct stat stat_buf;920 xstat("/var/lib/dpkg/status", &stat_buf);914 if (errno != ENOENT) 915 bb_error_msg_and_die("can't create backup status file"); 921 916 /* Its ok if renaming the status file fails because status 922 917 * file doesnt exist, maybe we are starting from scratch */ … … 924 919 } 925 920 926 if (rename("/var/lib/dpkg/status.udeb", "/var/lib/dpkg/status") == -1) { 927 bb_error_msg_and_die("DANGER: cannot create status file, " 928 "you need to manually repair your status file"); 929 } 921 xrename("/var/lib/dpkg/status.udeb", "/var/lib/dpkg/status"); 930 922 } 931 923 … … 948 940 949 941 switch (depend_type) { 950 case EDGE_PRE_DEPENDS: 951 case EDGE_DEPENDS: 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"); 952 944 } 953 945 return 0; 954 946 } 955 947 956 static int check_deps(deb_file_t **deb_file, int deb_start , int dep_max_count)948 static int check_deps(deb_file_t **deb_file, int deb_start /*, int dep_max_count - ?? */) 957 949 { 958 950 int *conflicts = NULL; … … 972 964 while (deb_file[i] != NULL) { 973 965 const unsigned package_num = deb_file[i]->package; 974 conflicts = xrealloc (conflicts, sizeof(int) * (conflicts_num + 1));966 conflicts = xrealloc_vector(conflicts, 2, conflicts_num); 975 967 conflicts[conflicts_num] = package_num; 976 968 conflicts_num++; 977 969 /* add provides to conflicts list */ 978 for (j = 0; j < 970 for (j = 0; j < package_hashtable[package_num]->num_of_edges; j++) { 979 971 if (package_hashtable[package_num]->edge[j]->type == EDGE_PROVIDES) { 980 972 const int conflicts_package_num = search_package_hashtable( … … 989 981 package_hashtable[conflicts_package_num] = new_node; 990 982 } 991 conflicts = xrealloc (conflicts, sizeof(int) * (conflicts_num + 1));983 conflicts = xrealloc_vector(conflicts, 2, conflicts_num); 992 984 conflicts[conflicts_num] = conflicts_package_num; 993 985 conflicts_num++; … … 1076 1068 if (package_edge->type == EDGE_OR_PRE_DEPENDS 1077 1069 || package_edge->type == EDGE_OR_DEPENDS 1078 ) { /* start an EDGE_OR_ list */ 1070 ) { 1071 /* start an EDGE_OR_ list */ 1079 1072 number_of_alternatives = package_edge->version; 1080 1073 root_of_alternatives = package_edge; 1081 1074 continue; 1082 1075 } 1083 if (number_of_alternatives == 0) { 1076 if (number_of_alternatives == 0) { /* not in the middle of an EDGE_OR_ list */ 1084 1077 number_of_alternatives = 1; 1085 1078 root_of_alternatives = NULL; … … 1088 1081 package_num = search_package_hashtable(package_edge->name, package_edge->version, package_edge->operator); 1089 1082 1090 if (package_edge->type == EDGE_PRE_DEPENDS || 1091 package_edge->type == EDGE_DEPENDS) { 1083 if (package_edge->type == EDGE_PRE_DEPENDS 1084 || package_edge->type == EDGE_DEPENDS 1085 ) { 1092 1086 int result=1; 1093 1087 status_num = 0; … … 1157 1151 { 1158 1152 FILE *list_stream; 1159 char **file_list = NULL;1160 char *line = NULL;1161 int count = 0;1153 char **file_list; 1154 char *line; 1155 int count; 1162 1156 1163 1157 /* don't use [xw]fopen here, handle error ourself */ 1164 list_stream = fopen (filename, "r");1158 list_stream = fopen_for_read(filename); 1165 1159 if (list_stream == NULL) { 1166 1160 return NULL; 1167 1161 } 1168 1162 1169 while ((line = xmalloc_getline(list_stream)) != NULL) { 1170 file_list = xrealloc(file_list, sizeof(char *) * (count + 2)); 1171 file_list[count] = line; 1172 count++; 1163 file_list = NULL; 1164 count = 0; 1165 while ((line = xmalloc_fgetline(list_stream)) != NULL) { 1166 file_list = xrealloc_vector(file_list, 2, count); 1167 file_list[count++] = line; 1168 /*file_list[count] = NULL; - xrealloc_vector did it */ 1173 1169 } 1174 1170 fclose(list_stream); 1175 1171 1176 if (count == 0) {1177 return NULL;1178 }1179 file_list[count] = NULL;1180 1172 return file_list; 1181 1173 } … … 1214 1206 } 1215 1207 1216 static int run_package_script(const char *package_name, const char *script_type) 1217 { 1218 struct stat path_stat; 1208 static void run_package_script_or_die(const char *package_name, const char *script_type) 1209 { 1219 1210 char *script_path; 1220 1211 int result; … … 1222 1213 script_path = xasprintf("/var/lib/dpkg/info/%s.%s", package_name, script_type); 1223 1214 1224 /* If the file doesnt exist is isnt afatal */1225 result = lstat(script_path, &path_stat) < 0? EXIT_SUCCESS : system(script_path);1215 /* If the file doesnt exist is isnt fatal */ 1216 result = access(script_path, F_OK) ? EXIT_SUCCESS : system(script_path); 1226 1217 free(script_path); 1227 return result; 1228 } 1229 1218 if (result) 1219 bb_error_msg_and_die("%s failed, exit code %d", script_type, result); 1220 } 1221 1222 /* 1223 The policy manual defines what scripts get called when and with 1224 what arguments. I realize that busybox does not support all of 1225 these scenarios, but it does support some of them; it does not, 1226 however, run them with any parameters in run_package_script_or_die(). 1227 Here are the scripts: 1228 1229 preinst install 1230 preinst install <old_version> 1231 preinst upgrade <old_version> 1232 preinst abort_upgrade <new_version> 1233 postinst configure <most_recent_version> 1234 postinst abort-upgade <new_version> 1235 postinst abort-remove 1236 postinst abort-remove in-favour <package> <version> 1237 postinst abort-deconfigure in-favor <failed_install_package> removing <conflicting_package> <version> 1238 prerm remove 1239 prerm upgrade <new_version> 1240 prerm failed-upgrade <old_version> 1241 prerm remove in-favor <package> <new_version> 1242 prerm deconfigure in-favour <package> <version> removing <package> <version> 1243 postrm remove 1244 postrm purge 1245 postrm upgrade <new_version> 1246 postrm failed-upgrade <old_version> 1247 postrm abort-install 1248 postrm abort-install <old_version> 1249 postrm abort-upgrade <old_version> 1250 postrm disappear <overwriter> <version> 1251 */ 1230 1252 static const char *const all_control_files[] = { 1231 1253 "preinst", "postinst", "prerm", "postrm", 1232 1254 "list", "md5sums", "shlibs", "conffiles", 1233 "config", "templates" , NULL1255 "config", "templates" 1234 1256 }; 1235 1257 … … 1240 1262 1241 1263 /* Create a list of all /var/lib/dpkg/info/<package> files */ 1242 remove_files = xzalloc(sizeof(all_control_files)); 1243 while (all_control_files[i]) { 1244 remove_files[i] = xasprintf("/var/lib/dpkg/info/%s.%s", package_name, all_control_files[i]); 1264 remove_files = xzalloc(sizeof(all_control_files) + sizeof(char*)); 1265 while (i < ARRAY_SIZE(all_control_files)) { 1266 remove_files[i] = xasprintf("/var/lib/dpkg/info/%s.%s", 1267 package_name, all_control_files[i]); 1245 1268 i++; 1246 1269 } … … 1265 1288 * scanning the status file. The resulting list, however, is unsorted. 1266 1289 */ 1267 static void list_packages( void)1290 static void list_packages(const char *pattern) 1268 1291 { 1269 1292 int i; … … 1286 1309 vers_str = name_hashtable[package_hashtable[status_hashtable[i]->package]->version]; 1287 1310 1311 if (pattern && fnmatch(pattern, name_str, 0) != 0) 1312 continue; 1313 1288 1314 /* get abbreviation for status field 1 */ 1289 1315 s1 = stat_str[0] == 'i' ? 'i' : 'r'; … … 1315 1341 printf("Removing %s (%s)...\n", package_name, package_version); 1316 1342 1317 /* run prerm script */ 1318 if (run_package_script(package_name, "prerm") != 0) { 1319 bb_error_msg_and_die("script failed, prerm failure"); 1320 } 1343 /* Run prerm script */ 1344 run_package_script_or_die(package_name, "prerm"); 1321 1345 1322 1346 /* Create a list of files to remove, and a separate list of those to keep */ 1323 sprintf(list_name, "/var/lib/dpkg/info/%s. list", package_name);1347 sprintf(list_name, "/var/lib/dpkg/info/%s.%s", package_name, "list"); 1324 1348 remove_files = create_list(list_name); 1325 1349 1326 sprintf(conffile_name, "/var/lib/dpkg/info/%s. conffiles", package_name);1350 sprintf(conffile_name, "/var/lib/dpkg/info/%s.%s", package_name, "conffiles"); 1327 1351 exclude_files = create_list(conffile_name); 1328 1352 1329 1353 /* Some directories can't be removed straight away, so do multiple passes */ 1330 while (remove_file_array(remove_files, exclude_files)) /*repeat */; 1354 while (remove_file_array(remove_files, exclude_files)) 1355 continue; 1331 1356 free_array(exclude_files); 1332 1357 free_array(remove_files); 1333 1358 1334 /* Create a list of files in /var/lib/dpkg/info/<package>.* to keep 1335 exclude_files = xzalloc(sizeof( char*) * 3);1359 /* Create a list of files in /var/lib/dpkg/info/<package>.* to keep */ 1360 exclude_files = xzalloc(sizeof(exclude_files[0]) * 3); 1336 1361 exclude_files[0] = xstrdup(conffile_name); 1337 exclude_files[1] = xasprintf("/var/lib/dpkg/info/%s. postrm", package_name);1362 exclude_files[1] = xasprintf("/var/lib/dpkg/info/%s.%s", package_name, "postrm"); 1338 1363 1339 1364 /* Create a list of all /var/lib/dpkg/info/<package> files */ … … 1344 1369 free_array(exclude_files); 1345 1370 1346 /* rename <package>.conffile to <package>.list */ 1371 /* rename <package>.conffiles to <package>.list 1372 * The conffiles control file isn't required in Debian packages, so don't 1373 * error out if it's missing. */ 1347 1374 rename(conffile_name, list_name); 1348 1375 … … 1362 1389 printf("Purging %s (%s)...\n", package_name, package_version); 1363 1390 1364 /* run prerm script */ 1365 if (run_package_script(package_name, "prerm") != 0) { 1366 bb_error_msg_and_die("script failed, prerm failure"); 1367 } 1391 /* Run prerm script */ 1392 run_package_script_or_die(package_name, "prerm"); 1368 1393 1369 1394 /* Create a list of files to remove */ 1370 sprintf(list_name, "/var/lib/dpkg/info/%s. list", package_name);1395 sprintf(list_name, "/var/lib/dpkg/info/%s.%s", package_name, "list"); 1371 1396 remove_files = create_list(list_name); 1372 1397 1373 exclude_files = xzalloc(sizeof(char*));1374 1375 1398 /* Some directories cant be removed straight away, so do multiple passes */ 1376 while (remove_file_array(remove_files, exclude_files)) /* repeat */; 1399 while (remove_file_array(remove_files, NULL)) 1400 continue; 1377 1401 free_array(remove_files); 1378 1402 1379 1403 /* Create a list of all /var/lib/dpkg/info/<package> files */ 1380 1404 remove_files = all_control_list(package_name); 1405 1406 /* Delete all of them except the postrm script */ 1407 exclude_files = xzalloc(sizeof(exclude_files[0]) * 2); 1408 exclude_files[0] = xasprintf("/var/lib/dpkg/info/%s.%s", package_name, "postrm"); 1381 1409 remove_file_array(remove_files, exclude_files); 1410 free_array(exclude_files); 1411 1412 /* Run and remove postrm script */ 1413 run_package_script_or_die(package_name, "postrm"); 1414 remove_file_array(remove_files, NULL); 1415 1382 1416 free_array(remove_files); 1383 free(exclude_files);1384 1385 /* run postrm script */1386 if (run_package_script(package_name, "postrm") != 0) {1387 bb_error_msg_and_die("postrm failure.. set status to what?");1388 }1389 1417 1390 1418 /* Change package status */ … … 1413 1441 1414 1442 /* We don't care about data.tar.* or debian-binary, just control.tar.* */ 1415 #if ENABLE_FEATURE_ DEB_TAR_GZ1443 #if ENABLE_FEATURE_SEAMLESS_GZ 1416 1444 llist_add_to(&(ar_handle->accept), (char*)"control.tar.gz"); 1417 1445 #endif 1418 #if ENABLE_FEATURE_ DEB_TAR_BZ21446 #if ENABLE_FEATURE_SEAMLESS_BZ2 1419 1447 llist_add_to(&(ar_handle->accept), (char*)"control.tar.bz2"); 1420 1448 #endif 1421 1449 1422 1450 /* Assign the tar handle as a subarchive of the ar handle */ 1423 ar_handle-> sub_archive = tar_handle;1451 ar_handle->dpkg__sub_archive = tar_handle; 1424 1452 } 1425 1453 … … 1433 1461 1434 1462 /* We don't care about control.tar.* or debian-binary, just data.tar.* */ 1435 #if ENABLE_FEATURE_ DEB_TAR_GZ1463 #if ENABLE_FEATURE_SEAMLESS_GZ 1436 1464 llist_add_to(&(ar_handle->accept), (char*)"data.tar.gz"); 1437 1465 #endif 1438 #if ENABLE_FEATURE_ DEB_TAR_BZ21466 #if ENABLE_FEATURE_SEAMLESS_BZ2 1439 1467 llist_add_to(&(ar_handle->accept), (char*)"data.tar.bz2"); 1440 1468 #endif 1441 1469 1442 1470 /* Assign the tar handle as a subarchive of the ar handle */ 1443 ar_handle->sub_archive = tar_handle; 1471 ar_handle->dpkg__sub_archive = tar_handle; 1472 } 1473 1474 static void FAST_FUNC data_extract_to_buffer(archive_handle_t *archive_handle) 1475 { 1476 unsigned size = archive_handle->file_header->size; 1477 1478 archive_handle->dpkg__buffer = xzalloc(size + 1); 1479 xread(archive_handle->src_fd, archive_handle->dpkg__buffer, size); 1444 1480 } 1445 1481 1446 1482 static char *deb_extract_control_file_to_buffer(archive_handle_t *ar_handle, llist_t *myaccept) 1447 1483 { 1448 ar_handle-> sub_archive->action_data = data_extract_to_buffer;1449 ar_handle-> sub_archive->accept = myaccept;1450 ar_handle-> sub_archive->filter = filter_accept_list;1484 ar_handle->dpkg__sub_archive->action_data = data_extract_to_buffer; 1485 ar_handle->dpkg__sub_archive->accept = myaccept; 1486 ar_handle->dpkg__sub_archive->filter = filter_accept_list; 1451 1487 1452 1488 unpack_ar_archive(ar_handle); 1453 1489 close(ar_handle->src_fd); 1454 1490 1455 return ar_handle->sub_archive->buffer; 1456 } 1457 1458 static void data_extract_all_prefix(archive_handle_t *archive_handle) 1491 return ar_handle->dpkg__sub_archive->dpkg__buffer; 1492 } 1493 1494 static void append_control_file_to_llist(const char *package_name, const char *control_name, llist_t **ll) 1495 { 1496 FILE *fp; 1497 char *filename, *line; 1498 1499 filename = xasprintf("/var/lib/dpkg/info/%s.%s", package_name, control_name); 1500 fp = fopen_for_read(filename); 1501 free(filename); 1502 if (fp != NULL) { 1503 while ((line = xmalloc_fgetline(fp)) != NULL) 1504 llist_add_to(ll, line); 1505 fclose(fp); 1506 } 1507 } 1508 1509 static char FAST_FUNC filter_rename_config(archive_handle_t *archive_handle) 1510 { 1511 int fd; 1512 char *name_ptr = archive_handle->file_header->name + 1; 1513 1514 /* Is this file marked as config file? */ 1515 if (!find_list_entry(archive_handle->accept, name_ptr)) 1516 return EXIT_SUCCESS; /* no */ 1517 1518 fd = open(name_ptr, O_RDONLY); 1519 if (fd >= 0) { 1520 md5_ctx_t md5; 1521 char *md5line, *buf; 1522 int count; 1523 1524 /* Calculate MD5 of existing file */ 1525 buf = xmalloc(4096); 1526 md5_begin(&md5); 1527 while ((count = safe_read(fd, buf, 4096)) > 0) 1528 md5_hash(&md5, buf, count); 1529 md5_end(&md5, buf); /* using buf as result storage */ 1530 close(fd); 1531 1532 md5line = xmalloc(16 * 2 + 2 + strlen(name_ptr) + 1); 1533 sprintf(bin2hex(md5line, buf, 16), " %s", name_ptr); 1534 free(buf); 1535 1536 /* Is it changed after install? */ 1537 if (find_list_entry(archive_handle->accept, md5line) == NULL) { 1538 printf("Warning: Creating %s as %s.dpkg-new\n", name_ptr, name_ptr); 1539 archive_handle->file_header->name = xasprintf("%s.dpkg-new", archive_handle->file_header->name); 1540 } 1541 free(md5line); 1542 } 1543 return EXIT_SUCCESS; 1544 } 1545 1546 static void FAST_FUNC data_extract_all_prefix(archive_handle_t *archive_handle) 1459 1547 { 1460 1548 char *name_ptr = archive_handle->file_header->name; 1461 1549 1462 name_ptr += strspn(name_ptr, "./"); 1550 /* Skip all leading "/" */ 1551 while (*name_ptr == '/') 1552 name_ptr++; 1553 /* Skip all leading "./" and "../" */ 1554 while (name_ptr[0] == '.') { 1555 if (name_ptr[1] == '.') 1556 name_ptr++; 1557 if (name_ptr[1] != '/') 1558 break; 1559 name_ptr += 2; 1560 } 1561 1463 1562 if (name_ptr[0] != '\0') { 1464 archive_handle->file_header->name = xasprintf("%s%s", archive_handle-> buffer, name_ptr);1563 archive_handle->file_header->name = xasprintf("%s%s", archive_handle->dpkg__buffer, name_ptr); 1465 1564 data_extract_all(archive_handle); 1466 } 1467 } 1565 if (fnmatch("*.dpkg-new", archive_handle->file_header->name, 0) == 0) { 1566 /* remove .dpkg-new suffix */ 1567 archive_handle->file_header->name[strlen(archive_handle->file_header->name) - 9] = '\0'; 1568 } 1569 } 1570 } 1571 1572 enum { 1573 /* Commands */ 1574 OPT_configure = (1 << 0), 1575 OPT_install = (1 << 1), 1576 OPT_list_installed = (1 << 2), 1577 OPT_purge = (1 << 3), 1578 OPT_remove = (1 << 4), 1579 OPT_unpack = (1 << 5), 1580 OPTMASK_cmd = (1 << 6) - 1, 1581 /* Options */ 1582 OPT_force = (1 << 6), 1583 OPT_force_ignore_depends = (1 << 7), 1584 OPT_force_confnew = (1 << 8), 1585 OPT_force_confold = (1 << 9), 1586 }; 1468 1587 1469 1588 static void unpack_package(deb_file_t *deb_file) … … 1476 1595 archive_handle_t *archive_handle; 1477 1596 FILE *out_stream; 1478 llist_t *accept_list = NULL; 1479 int i = 0; 1597 llist_t *accept_list; 1598 llist_t *conffile_list; 1599 int i; 1480 1600 1481 1601 /* If existing version, remove it first */ 1602 conffile_list = NULL; 1482 1603 if (strcmp(name_hashtable[get_status(status_num, 3)], "installed") == 0) { 1483 1604 /* Package is already installed, remove old version first */ … … 1485 1606 name_hashtable[package_hashtable[status_package_num]->version], 1486 1607 deb_file->filename); 1608 1609 /* Read md5sums from old package */ 1610 if (!(option_mask32 & OPT_force_confold)) 1611 append_control_file_to_llist(package_name, "md5sums", &conffile_list); 1612 1487 1613 remove_package(status_package_num, 0); 1488 1614 } else { … … 1491 1617 1492 1618 /* Extract control.tar.gz to /var/lib/dpkg/info/<package>.filename */ 1493 info_prefix = xasprintf("/var/lib/dpkg/info/%s. ", package_name);1619 info_prefix = xasprintf("/var/lib/dpkg/info/%s.%s", package_name, ""); 1494 1620 archive_handle = init_archive_deb_ar(deb_file->filename); 1495 1621 init_archive_deb_control(archive_handle); 1496 1622 1497 while (all_control_files[i]) { 1623 accept_list = NULL; 1624 i = 0; 1625 while (i < ARRAY_SIZE(all_control_files)) { 1498 1626 char *c = xasprintf("./%s", all_control_files[i]); 1499 1627 llist_add_to(&accept_list, c); 1500 1628 i++; 1501 1629 } 1502 archive_handle-> sub_archive->accept = accept_list;1503 archive_handle-> sub_archive->filter = filter_accept_list;1504 archive_handle-> sub_archive->action_data = data_extract_all_prefix;1505 archive_handle-> sub_archive->buffer = info_prefix;1506 archive_handle-> sub_archive->flags |= ARCHIVE_EXTRACT_UNCONDITIONAL;1630 archive_handle->dpkg__sub_archive->accept = accept_list; 1631 archive_handle->dpkg__sub_archive->filter = filter_accept_list; 1632 archive_handle->dpkg__sub_archive->action_data = data_extract_all_prefix; 1633 archive_handle->dpkg__sub_archive->dpkg__buffer = info_prefix; 1634 archive_handle->dpkg__sub_archive->ah_flags |= ARCHIVE_UNLINK_OLD; 1507 1635 unpack_ar_archive(archive_handle); 1508 1636 1509 1637 /* Run the preinst prior to extracting */ 1510 if (run_package_script(package_name, "preinst") != 0) { 1511 /* when preinst returns exit code != 0 then quit installation process */ 1512 bb_error_msg_and_die("subprocess pre-installation script returned error"); 1513 } 1638 run_package_script_or_die(package_name, "preinst"); 1639 1640 /* Don't overwrite existing config files */ 1641 if (!(option_mask32 & OPT_force_confnew)) 1642 append_control_file_to_llist(package_name, "conffiles", &conffile_list); 1514 1643 1515 1644 /* Extract data.tar.gz to the root directory */ 1516 1645 archive_handle = init_archive_deb_ar(deb_file->filename); 1517 1646 init_archive_deb_data(archive_handle); 1518 archive_handle->sub_archive->action_data = data_extract_all_prefix; 1519 archive_handle->sub_archive->buffer = (char*)"/"; /* huh? */ 1520 archive_handle->sub_archive->flags |= ARCHIVE_EXTRACT_UNCONDITIONAL; 1647 archive_handle->dpkg__sub_archive->accept = conffile_list; 1648 archive_handle->dpkg__sub_archive->filter = filter_rename_config; 1649 archive_handle->dpkg__sub_archive->action_data = data_extract_all_prefix; 1650 archive_handle->dpkg__sub_archive->dpkg__buffer = (char*)"/"; /* huh? */ 1651 archive_handle->dpkg__sub_archive->ah_flags |= ARCHIVE_UNLINK_OLD; 1521 1652 unpack_ar_archive(archive_handle); 1522 1653 1523 1654 /* Create the list file */ 1524 list_filename = xasprintf("/var/lib/dpkg/info/%s. list", package_name);1525 out_stream = xfopen (list_filename, "w");1526 while (archive_handle-> sub_archive->passed) {1655 list_filename = xasprintf("/var/lib/dpkg/info/%s.%s", package_name, "list"); 1656 out_stream = xfopen_for_write(list_filename); 1657 while (archive_handle->dpkg__sub_archive->passed) { 1527 1658 /* the leading . has been stripped by data_extract_all_prefix already */ 1528 fputs(archive_handle-> sub_archive->passed->data, out_stream);1659 fputs(archive_handle->dpkg__sub_archive->passed->data, out_stream); 1529 1660 fputc('\n', out_stream); 1530 archive_handle-> sub_archive->passed = archive_handle->sub_archive->passed->link;1661 archive_handle->dpkg__sub_archive->passed = archive_handle->dpkg__sub_archive->passed->link; 1531 1662 } 1532 1663 fclose(out_stream); … … 1549 1680 1550 1681 /* Run the postinst script */ 1551 if (run_package_script(package_name, "postinst") != 0) { 1552 /* TODO: handle failure gracefully */ 1553 bb_error_msg_and_die("postinst failure.. set status to what?"); 1554 } 1682 /* TODO: handle failure gracefully */ 1683 run_package_script_or_die(package_name, "postinst"); 1684 1555 1685 /* Change status to reflect success */ 1556 1686 set_status(status_num, "install", 1); … … 1558 1688 } 1559 1689 1560 int dpkg_main(int argc, char **argv) ;1561 int dpkg_main(int argc , char **argv)1690 int dpkg_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 1691 int dpkg_main(int argc UNUSED_PARAM, char **argv) 1562 1692 { 1563 1693 deb_file_t **deb_file = NULL; … … 1570 1700 int status_num; 1571 1701 int i; 1572 enum { 1573 OPT_configure = 0x1, 1574 OPT_force_ignore_depends = 0x2, 1575 OPT_install = 0x4, 1576 OPT_list_installed = 0x8, 1577 OPT_purge = 0x10, 1578 OPT_remove = 0x20, 1579 OPT_unpack = 0x40, 1580 }; 1581 1582 opt = getopt32(argv, "CF:ilPru", &str_f); 1702 #if ENABLE_LONG_OPTS 1703 static const char dpkg_longopts[] ALIGN1 = 1704 // FIXME: we use -C non-compatibly, should be: 1705 // "-C|--audit Check for broken package(s)" 1706 "configure\0" No_argument "C" 1707 "force\0" Required_argument "F" 1708 "install\0" No_argument "i" 1709 "list\0" No_argument "l" 1710 "purge\0" No_argument "P" 1711 "remove\0" No_argument "r" 1712 "unpack\0" No_argument "u" 1713 "force-depends\0" No_argument "\xff" 1714 "force-confnew\0" No_argument "\xfe" 1715 "force-confold\0" No_argument "\xfd" 1716 ; 1717 #endif 1718 1719 INIT_G(); 1720 1721 IF_LONG_OPTS(applet_long_options = dpkg_longopts); 1722 opt = getopt32(argv, "CilPruF:", &str_f); 1723 argv += optind; 1583 1724 //if (opt & OPT_configure) ... // -C 1584 if (opt & OPT_force_ignore_depends) { // -F (--force in official dpkg) 1585 if (strcmp(str_f, "depends")) 1586 opt &= ~OPT_force_ignore_depends; 1725 if (opt & OPT_force) { // -F (--force in official dpkg) 1726 if (strcmp(str_f, "depends") == 0) 1727 opt |= OPT_force_ignore_depends; 1728 else if (strcmp(str_f, "confnew") == 0) 1729 opt |= OPT_force_confnew; 1730 else if (strcmp(str_f, "confold") == 0) 1731 opt |= OPT_force_confold; 1732 else 1733 bb_show_usage(); 1734 option_mask32 = opt; 1587 1735 } 1588 1736 //if (opt & OPT_install) ... // -i … … 1591 1739 //if (opt & OPT_remove) ... // -r 1592 1740 //if (opt & OPT_unpack) ... // -u (--unpack in official dpkg) 1593 argc -= optind; 1594 argv += optind; 1595 /* check for non-option argument if expected */ 1596 if (!opt || (!argc && !(opt && OPT_list_installed))) 1741 if (!(opt & OPTMASK_cmd) /* no cmd */ 1742 || ((opt & OPTMASK_cmd) & ((opt & OPTMASK_cmd)-1)) /* more than one cmd */ 1743 ) { 1597 1744 bb_show_usage(); 1598 1599 name_hashtable = xzalloc(sizeof(name_hashtable[0]) * (NAME_HASH_PRIME + 1)); 1600 package_hashtable = xzalloc(sizeof(package_hashtable[0]) * (PACKAGE_HASH_PRIME + 1)); 1601 status_hashtable = xzalloc(sizeof(status_hashtable[0]) * (STATUS_HASH_PRIME + 1)); 1745 } 1602 1746 1603 1747 /* puts("(Reading database ... xxxxx files and directories installed.)"); */ … … 1606 1750 /* if the list action was given print the installed packages and exit */ 1607 1751 if (opt & OPT_list_installed) { 1608 list_packages( );1752 list_packages(argv[0]); /* param can be NULL */ 1609 1753 return EXIT_SUCCESS; 1610 1754 } … … 1613 1757 while (*argv) { 1614 1758 /* deb_count = nb_elem - 1 and we need nb_elem + 1 to allocate terminal node [NULL pointer] */ 1615 deb_file = xrealloc (deb_file, sizeof(deb_file[0]) * (deb_count + 2));1759 deb_file = xrealloc_vector(deb_file, 2, deb_count); 1616 1760 deb_file[deb_count] = xzalloc(sizeof(deb_file[0][0])); 1617 1761 if (opt & (OPT_install | OPT_unpack)) { … … 1626 1770 deb_file[deb_count]->control_file = deb_extract_control_file_to_buffer(archive_handle, control_list); 1627 1771 if (deb_file[deb_count]->control_file == NULL) { 1628 bb_error_msg_and_die("can not extract control file");1772 bb_error_msg_and_die("can't extract control file"); 1629 1773 } 1630 1774 deb_file[deb_count]->filename = xstrdup(argv[0]); … … 1694 1838 /* Check that the deb file arguments are installable */ 1695 1839 if (!(opt & OPT_force_ignore_depends)) { 1696 if (!check_deps(deb_file, 0 , deb_count)) {1840 if (!check_deps(deb_file, 0 /*, deb_count*/)) { 1697 1841 bb_error_msg_and_die("dependency check failed"); 1698 1842 }
Note:
See TracChangeset
for help on using the changeset viewer.