Changeset 2725 in MondoRescue for branches/2.2.9/mindi-busybox/archival/dpkg.c


Ignore:
Timestamp:
Feb 25, 2011, 9:26:54 PM (13 years ago)
Author:
Bruno Cornec
Message:
  • Update mindi-busybox to 1.18.3 to avoid problems with the tar command which is now failing on recent versions with busybox 1.7.3
File:
1 edited

Legend:

Unmodified
Added
Removed
  • branches/2.2.9/mindi-busybox/archival/dpkg.c

    r1765 r2725  
    77 *  copyright (c) 2001 by glenn mcgrath
    88 *
     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 *
    913 *  started life as a busybox implementation of udpkg
    1014 *
    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.
    1216 */
    1317
     
    2630
    2731#include "libbb.h"
    28 #include "unarchive.h"
     32#include <fnmatch.h>
     33#include "archive.h"
    2934
    3035/* note: if you vary hash_prime sizes be aware,
     
    7681} status_node_t;
    7782
    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 */
     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
    8298
    8399/* Even numbers are for 'extras', like ored dependencies or null */
     
    124140         * shift amount is mod 24 because long int is 32 bit and data
    125141         * 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);
    128144    }
    129145    *start = (unsigned) hash_num % hash_prime;
     
    134150static int search_name_hashtable(const char *key)
    135151{
    136     unsigned probe_address = 0;
    137     unsigned probe_decrement = 0;
     152    unsigned probe_address;
     153    unsigned probe_decrement;
    138154
    139155    make_hash(key, &probe_address, &probe_decrement, NAME_HASH_PRIME);
     
    156172static unsigned search_status_hashtable(const char *key)
    157173{
    158     unsigned probe_address = 0;
    159     unsigned probe_decrement = 0;
     174    unsigned probe_address;
     175    unsigned probe_decrement;
    160176
    161177    make_hash(key, &probe_address, &probe_decrement, STATUS_HASH_PRIME);
     
    172188}
    173189
    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) {
     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))
    223233            return -1;
    224         }
    225         if (ver_num1 > ver_num2) {
    226             return 1;
    227         }
     234        if (first_diff)
     235            return first_diff;
    228236    }
    229237    return 0;
     
    238246    char *ch_ver1 = name_hashtable[ver1];
    239247    char *ch_ver2 = name_hashtable[ver2];
    240 
    241     char epoch1, epoch2;
     248    unsigned epoch1 = 0, epoch2 = 0;
     249    char *colon;
    242250    char *deb_ver1, *deb_ver2;
    243     char *ver1_ptr, *ver2_ptr;
    244251    char *upstream_ver1;
    245252    char *upstream_ver2;
     
    247254
    248255    /* 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;
    262265    }
    263266    if (epoch1 < epoch2) {
    264267        return -1;
    265268    }
    266     else if (epoch1 > epoch2) {
     269    if (epoch1 > epoch2) {
    267270        return 1;
    268271    }
    269272
    270273    /* 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);
    273276
    274277    /* Chop off debian version, and store for later use */
     
    276279    deb_ver2 = strrchr(upstream_ver2, '-');
    277280    if (deb_ver1) {
    278         deb_ver1[0] = '\0';
    279         deb_ver1++;
     281        *deb_ver1++ = '\0';
    280282    }
    281283    if (deb_ver2) {
    282         deb_ver2[0] = '\0';
    283         deb_ver2++;
     284        *deb_ver2++ = '\0';
    284285    }
    285286    result = version_compare_part(upstream_ver1, upstream_ver2);
    286     if (!result)
     287    if (result == 0) {
    287288        /* Compare debian versions */
    288289        result = version_compare_part(deb_ver1, deb_ver2);
     290    }
    289291
    290292    free(upstream_ver1);
     
    313315}
    314316
    315 
    316317static int search_package_hashtable(const unsigned name, const unsigned version, const unsigned operator)
    317318{
    318     unsigned probe_address = 0;
    319     unsigned probe_decrement = 0;
     319    unsigned probe_address;
     320    unsigned probe_decrement;
    320321
    321322    make_hash(name_hashtable[name], &probe_address, &probe_decrement, PACKAGE_HASH_PRIME);
     
    373374static void add_edge_to_node(common_node_t *node, edge_t *edge)
    374375{
    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;
    378378}
    379379
     
    411411         && (strcmp(field, field2) != 0)
    412412        ) {
    413             or_edge = xmalloc(sizeof(edge_t));
     413            or_edge = xzalloc(sizeof(edge_t));
    414414            or_edge->type = edge_type + 1;
    415415            or_edge->name = search_name_hashtable(field);
    416             or_edge->version = 0; // tracks the number of alternatives
     416            //or_edge->version = 0; // tracks the number of alternatives
    417417            add_edge_to_node(parent_node, or_edge);
    418418        }
     
    440440                    if (strncmp(version, "=", offset_ch) == 0) {
    441441                        edge->operator = VER_EQUAL;
    442                     }
    443                     else if (strncmp(version, "<<", offset_ch) == 0) {
     442                    } else if (strncmp(version, "<<", offset_ch) == 0) {
    444443                        edge->operator = VER_LESS;
    445                     }
    446                     else if (strncmp(version, "<=", offset_ch) == 0) {
     444                    } else if (strncmp(version, "<=", offset_ch) == 0) {
    447445                        edge->operator = VER_LESS_EQUAL;
    448                     }
    449                     else if (strncmp(version, ">>", offset_ch) == 0) {
     446                    } else if (strncmp(version, ">>", offset_ch) == 0) {
    450447                        edge->operator = VER_MORE;
    451                     }
    452                     else if (strncmp(version, ">=", offset_ch) == 0) {
     448                    } else if (strncmp(version, ">=", offset_ch) == 0) {
    453449                        edge->operator = VER_MORE_EQUAL;
    454450                    } else {
     
    497493
    498494/*
    499  * Gets the next package field from package_buffer, seperated into the field name
     495 * Gets the next package field from package_buffer, separated into the field name
    500496 * and field value, it returns the int offset to the first character of the next field
    501497 */
     
    603599
    604600        if (field_name == NULL) {
    605             goto fill_package_struct_cleanup; /* Oh no, the dreaded goto statement! */
     601            goto fill_package_struct_cleanup;
    606602        }
    607603
     
    736732}
    737733
    738 
    739734static void index_status_file(const char *filename)
    740735{
     
    745740    unsigned status_num;
    746741
    747     status_file = xfopen(filename, "r");
    748     while ((control_buffer = xmalloc_fgets_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) {
    749744        const unsigned package_num = fill_package_struct(control_buffer);
    750745        if (package_num != -1) {
     
    787782static void write_status_file(deb_file_t **deb_file)
    788783{
    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");
    791786    char *package_name;
    792787    char *status_from_file;
     
    799794
    800795    /* Update previously known packages */
    801     while ((control_buffer = xmalloc_fgets_str(old_status_file, "\n\n")) != NULL) {
     796    while ((control_buffer = xmalloc_fgetline_str(old_status_file, "\n\n")) != NULL) {
    802797        tmp_string = strstr(control_buffer, "Package:");
    803798        if (tmp_string == NULL) {
     
    811806        tmp_string = strstr(control_buffer, "Status:");
    812807        if (tmp_string != NULL) {
    813             /* Seperate the status value from the control buffer */
     808            /* Separate the status value from the control buffer */
    814809            tmp_string += 7;
    815810            tmp_string += strspn(tmp_string, " \n\t");
     
    863858                            break;
    864859                        }
    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                        ) {
    867863                            fprintf(new_status_file, "%s: %s\n", field_name, field_value);
    868864                        }
     
    871867                    fputs("\n", new_status_file);
    872868                }
    873                 else if (strcmp("config-files", name_hashtable[state_status]) == 0) {
     869                else if (strcmp("config-files", name_hashtable[state_status]) == 0) {
    874870                    /* only change the status line */
    875871                    while (1) {
     
    914910    fclose(new_status_file);
    915911
    916 
    917912    /* Create a separate backfile to dpkg */
    918913    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");
    921916        /* Its ok if renaming the status file fails because status
    922917         * file doesnt exist, maybe we are starting from scratch */
     
    924919    }
    925920
    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");
    930922}
    931923
     
    948940
    949941    switch (depend_type) {
    950     case EDGE_PRE_DEPENDS:  return get_status(status_num, 3) == search_name_hashtable("installed");
    951     case EDGE_DEPENDS:  return get_status(status_num, 1) == search_name_hashtable("install");
     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");
    952944    }
    953945    return 0;
    954946}
    955947
    956 static int check_deps(deb_file_t **deb_file, int deb_start, int dep_max_count)
     948static int check_deps(deb_file_t **deb_file, int deb_start /*, int dep_max_count - ?? */)
    957949{
    958950    int *conflicts = NULL;
     
    972964    while (deb_file[i] != NULL) {
    973965        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);
    975967        conflicts[conflicts_num] = package_num;
    976968        conflicts_num++;
    977969        /* add provides to conflicts list */
    978         for (j = 0; j < package_hashtable[package_num]->num_of_edges; j++) {
     970        for (j = 0; j < package_hashtable[package_num]->num_of_edges; j++) {
    979971            if (package_hashtable[package_num]->edge[j]->type == EDGE_PROVIDES) {
    980972                const int conflicts_package_num = search_package_hashtable(
     
    989981                    package_hashtable[conflicts_package_num] = new_node;
    990982                }
    991                 conflicts = xrealloc(conflicts, sizeof(int) * (conflicts_num + 1));
     983                conflicts = xrealloc_vector(conflicts, 2, conflicts_num);
    992984                conflicts[conflicts_num] = conflicts_package_num;
    993985                conflicts_num++;
     
    10761068            if (package_edge->type == EDGE_OR_PRE_DEPENDS
    10771069             || package_edge->type == EDGE_OR_DEPENDS
    1078             ) { /* start an EDGE_OR_ list */
     1070            ) {
     1071                /* start an EDGE_OR_ list */
    10791072                number_of_alternatives = package_edge->version;
    10801073                root_of_alternatives = package_edge;
    10811074                continue;
    10821075            }
    1083             if (number_of_alternatives == 0) {  /* not in the middle of an EDGE_OR_ list */
     1076            if (number_of_alternatives == 0) {  /* not in the middle of an EDGE_OR_ list */
    10841077                number_of_alternatives = 1;
    10851078                root_of_alternatives = NULL;
     
    10881081            package_num = search_package_hashtable(package_edge->name, package_edge->version, package_edge->operator);
    10891082
    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            ) {
    10921086                int result=1;
    10931087                status_num = 0;
     
    11571151{
    11581152    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;
    11621156
    11631157    /* don't use [xw]fopen here, handle error ourself */
    1164     list_stream = fopen(filename, "r");
     1158    list_stream = fopen_for_read(filename);
    11651159    if (list_stream == NULL) {
    11661160        return NULL;
    11671161    }
    11681162
    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 */
    11731169    }
    11741170    fclose(list_stream);
    11751171
    1176     if (count == 0) {
    1177         return NULL;
    1178     }
    1179     file_list[count] = NULL;
    11801172    return file_list;
    11811173}
     
    12141206}
    12151207
    1216 static int run_package_script(const char *package_name, const char *script_type)
    1217 {
    1218     struct stat path_stat;
     1208static void run_package_script_or_die(const char *package_name, const char *script_type)
     1209{
    12191210    char *script_path;
    12201211    int result;
     
    12221213    script_path = xasprintf("/var/lib/dpkg/info/%s.%s", package_name, script_type);
    12231214
    1224     /* If the file doesnt exist is isnt a fatal */
    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);
    12261217    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/*
     1223The policy manual defines what scripts get called when and with
     1224what arguments. I realize that busybox does not support all of
     1225these scenarios, but it does support some of them; it does not,
     1226however, run them with any parameters in run_package_script_or_die().
     1227Here are the scripts:
     1228
     1229preinst install
     1230preinst install <old_version>
     1231preinst upgrade <old_version>
     1232preinst abort_upgrade <new_version>
     1233postinst configure <most_recent_version>
     1234postinst abort-upgade <new_version>
     1235postinst abort-remove
     1236postinst abort-remove in-favour <package> <version>
     1237postinst abort-deconfigure in-favor <failed_install_package> removing <conflicting_package> <version>
     1238prerm remove
     1239prerm upgrade <new_version>
     1240prerm failed-upgrade <old_version>
     1241prerm remove in-favor <package> <new_version>
     1242prerm deconfigure in-favour <package> <version> removing <package> <version>
     1243postrm remove
     1244postrm purge
     1245postrm upgrade <new_version>
     1246postrm failed-upgrade <old_version>
     1247postrm abort-install
     1248postrm abort-install <old_version>
     1249postrm abort-upgrade <old_version>
     1250postrm disappear <overwriter> <version>
     1251*/
    12301252static const char *const all_control_files[] = {
    12311253    "preinst", "postinst", "prerm", "postrm",
    12321254    "list", "md5sums", "shlibs", "conffiles",
    1233     "config", "templates", NULL
     1255    "config", "templates"
    12341256};
    12351257
     
    12401262
    12411263    /* 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]);
    12451268        i++;
    12461269    }
     
    12651288 * scanning the status file. The resulting list, however, is unsorted.
    12661289 */
    1267 static void list_packages(void)
     1290static void list_packages(const char *pattern)
    12681291{
    12691292    int i;
     
    12861309            vers_str = name_hashtable[package_hashtable[status_hashtable[i]->package]->version];
    12871310
     1311            if (pattern && fnmatch(pattern, name_str, 0) != 0)
     1312                continue;
     1313
    12881314            /* get abbreviation for status field 1 */
    12891315            s1 = stat_str[0] == 'i' ? 'i' : 'r';
     
    13151341        printf("Removing %s (%s)...\n", package_name, package_version);
    13161342
    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");
    13211345
    13221346    /* 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");
    13241348    remove_files = create_list(list_name);
    13251349
    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");
    13271351    exclude_files = create_list(conffile_name);
    13281352
    13291353    /* 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;
    13311356    free_array(exclude_files);
    13321357    free_array(remove_files);
    13331358
    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);
    13361361    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");
    13381363
    13391364    /* Create a list of all /var/lib/dpkg/info/<package> files */
     
    13441369    free_array(exclude_files);
    13451370
    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.  */
    13471374    rename(conffile_name, list_name);
    13481375
     
    13621389    printf("Purging %s (%s)...\n", package_name, package_version);
    13631390
    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");
    13681393
    13691394    /* 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");
    13711396    remove_files = create_list(list_name);
    13721397
    1373     exclude_files = xzalloc(sizeof(char*));
    1374 
    13751398    /* 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;
    13771401    free_array(remove_files);
    13781402
    13791403    /* Create a list of all /var/lib/dpkg/info/<package> files */
    13801404    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");
    13811409    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
    13821416    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     }
    13891417
    13901418    /* Change package status */
     
    14131441
    14141442    /* We don't care about data.tar.* or debian-binary, just control.tar.* */
    1415 #if ENABLE_FEATURE_DEB_TAR_GZ
     1443#if ENABLE_FEATURE_SEAMLESS_GZ
    14161444    llist_add_to(&(ar_handle->accept), (char*)"control.tar.gz");
    14171445#endif
    1418 #if ENABLE_FEATURE_DEB_TAR_BZ2
     1446#if ENABLE_FEATURE_SEAMLESS_BZ2
    14191447    llist_add_to(&(ar_handle->accept), (char*)"control.tar.bz2");
    14201448#endif
    14211449
    14221450    /* 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;
    14241452}
    14251453
     
    14331461
    14341462    /* We don't care about control.tar.* or debian-binary, just data.tar.* */
    1435 #if ENABLE_FEATURE_DEB_TAR_GZ
     1463#if ENABLE_FEATURE_SEAMLESS_GZ
    14361464    llist_add_to(&(ar_handle->accept), (char*)"data.tar.gz");
    14371465#endif
    1438 #if ENABLE_FEATURE_DEB_TAR_BZ2
     1466#if ENABLE_FEATURE_SEAMLESS_BZ2
    14391467    llist_add_to(&(ar_handle->accept), (char*)"data.tar.bz2");
    14401468#endif
    14411469
    14421470    /* 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
     1474static 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);
    14441480}
    14451481
    14461482static char *deb_extract_control_file_to_buffer(archive_handle_t *ar_handle, llist_t *myaccept)
    14471483{
    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;
    14511487
    14521488    unpack_ar_archive(ar_handle);
    14531489    close(ar_handle->src_fd);
    14541490
    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
     1494static 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
     1509static 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
     1546static void FAST_FUNC data_extract_all_prefix(archive_handle_t *archive_handle)
    14591547{
    14601548    char *name_ptr = archive_handle->file_header->name;
    14611549
    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
    14631562    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);
    14651564        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
     1572enum {
     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};
    14681587
    14691588static void unpack_package(deb_file_t *deb_file)
     
    14761595    archive_handle_t *archive_handle;
    14771596    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;
    14801600
    14811601    /* If existing version, remove it first */
     1602    conffile_list = NULL;
    14821603    if (strcmp(name_hashtable[get_status(status_num, 3)], "installed") == 0) {
    14831604        /* Package is already installed, remove old version first */
     
    14851606            name_hashtable[package_hashtable[status_package_num]->version],
    14861607            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
    14871613        remove_package(status_package_num, 0);
    14881614    } else {
     
    14911617
    14921618    /* 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, "");
    14941620    archive_handle = init_archive_deb_ar(deb_file->filename);
    14951621    init_archive_deb_control(archive_handle);
    14961622
    1497     while (all_control_files[i]) {
     1623    accept_list = NULL;
     1624    i = 0;
     1625    while (i < ARRAY_SIZE(all_control_files)) {
    14981626        char *c = xasprintf("./%s", all_control_files[i]);
    14991627        llist_add_to(&accept_list, c);
    15001628        i++;
    15011629    }
    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;
    15071635    unpack_ar_archive(archive_handle);
    15081636
    15091637    /* 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);
    15141643
    15151644    /* Extract data.tar.gz to the root directory */
    15161645    archive_handle = init_archive_deb_ar(deb_file->filename);
    15171646    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;
    15211652    unpack_ar_archive(archive_handle);
    15221653
    15231654    /* 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) {
    15271658        /* 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);
    15291660        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;
    15311662    }
    15321663    fclose(out_stream);
     
    15491680
    15501681    /* 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
    15551685    /* Change status to reflect success */
    15561686    set_status(status_num, "install", 1);
     
    15581688}
    15591689
    1560 int dpkg_main(int argc, char **argv);
    1561 int dpkg_main(int argc, char **argv)
     1690int dpkg_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
     1691int dpkg_main(int argc UNUSED_PARAM, char **argv)
    15621692{
    15631693    deb_file_t **deb_file = NULL;
     
    15701700    int status_num;
    15711701    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;
    15831724    //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;
    15871735    }
    15881736    //if (opt & OPT_install) ... // -i
     
    15911739    //if (opt & OPT_remove) ... // -r
    15921740    //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    ) {
    15971744        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    }
    16021746
    16031747/*  puts("(Reading database ... xxxxx files and directories installed.)"); */
     
    16061750    /* if the list action was given print the installed packages and exit */
    16071751    if (opt & OPT_list_installed) {
    1608         list_packages();
     1752        list_packages(argv[0]); /* param can be NULL */
    16091753        return EXIT_SUCCESS;
    16101754    }
     
    16131757    while (*argv) {
    16141758        /* 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);
    16161760        deb_file[deb_count] = xzalloc(sizeof(deb_file[0][0]));
    16171761        if (opt & (OPT_install | OPT_unpack)) {
     
    16261770            deb_file[deb_count]->control_file = deb_extract_control_file_to_buffer(archive_handle, control_list);
    16271771            if (deb_file[deb_count]->control_file == NULL) {
    1628                 bb_error_msg_and_die("cannot extract control file");
     1772                bb_error_msg_and_die("can't extract control file");
    16291773            }
    16301774            deb_file[deb_count]->filename = xstrdup(argv[0]);
     
    16941838    /* Check that the deb file arguments are installable */
    16951839    if (!(opt & OPT_force_ignore_depends)) {
    1696         if (!check_deps(deb_file, 0, deb_count)) {
     1840        if (!check_deps(deb_file, 0 /*, deb_count*/)) {
    16971841            bb_error_msg_and_die("dependency check failed");
    16981842        }
Note: See TracChangeset for help on using the changeset viewer.