cli: implement --force-checksum
[oweals/opkg-lede.git] / libopkg / opkg_install.c
index 94d61884125507ebdb464cf4235884b07e7931f2..2c61a5fccd7b12f8d1598098030aaa702cf1b792 100644 (file)
    General Public License for more details.
 */
 
    General Public License for more details.
 */
 
-#include "includes.h"
-#include <errno.h>
-#include <dirent.h>
-#include <glob.h>
+#include "config.h"
+
+#include <stdio.h>
 #include <time.h>
 #include <signal.h>
 #include <time.h>
 #include <signal.h>
+#include <unistd.h>
+#include <sys/stat.h>
 
 #include "pkg.h"
 #include "pkg_hash.h"
 
 #include "pkg.h"
 #include "pkg_hash.h"
@@ -50,7 +51,7 @@ satisfy_dependencies_for(pkg_t *pkg)
      char **tmp, **unresolved = NULL;
      int ndepends;
 
      char **tmp, **unresolved = NULL;
      int ndepends;
 
-     ndepends = pkg_hash_fetch_unsatisfied_dependencies(pkg, depends, 
+     ndepends = pkg_hash_fetch_unsatisfied_dependencies(pkg, depends,
                                                        &unresolved);
 
      if (unresolved) {
                                                        &unresolved);
 
      if (unresolved) {
@@ -58,12 +59,12 @@ satisfy_dependencies_for(pkg_t *pkg)
                       pkg->name);
          tmp = unresolved;
          while (*unresolved) {
                       pkg->name);
          tmp = unresolved;
          while (*unresolved) {
-              opkg_msg(ERROR, "\t%s", *unresolved);
+              opkg_message(ERROR, "\t%s", *unresolved);
               free(*unresolved);
               unresolved++;
          }
          free(tmp);
               free(*unresolved);
               unresolved++;
          }
          free(tmp);
-         opkg_msg(ERROR, "\n");
+         opkg_message(ERROR, "\n");
          if (! conf->force_depends) {
               opkg_msg(INFO,
                            "This could mean that your package list is out of date or that the packages\n"
          if (! conf->force_depends) {
               opkg_msg(INFO,
                            "This could mean that your package list is out of date or that the packages\n"
@@ -134,7 +135,7 @@ check_conflicts_for(pkg_t *pkg)
          i = 0;
          while (i < conflicts->len)
               opkg_msg(level, "\t%s", conflicts->pkgs[i++]->name);
          i = 0;
          while (i < conflicts->len)
               opkg_msg(level, "\t%s", conflicts->pkgs[i++]->name);
-         opkg_msg(level, "\n");
+         opkg_message(level, "\n");
          pkg_vec_free(conflicts);
          return -1;
      }
          pkg_vec_free(conflicts);
          return -1;
      }
@@ -151,14 +152,17 @@ update_file_ownership(pkg_t *new_pkg, pkg_t *old_pkg)
      if (new_list == NULL)
             return -1;
 
      if (new_list == NULL)
             return -1;
 
-     for (iter = str_list_first(new_list), niter = str_list_next(new_list, iter); 
-             iter; 
+     for (iter = str_list_first(new_list), niter = str_list_next(new_list, iter);
+             iter;
              iter = niter, niter = str_list_next(new_list, niter)) {
          char *new_file = (char *)iter->data;
          pkg_t *owner = file_hash_get_file_owner(new_file);
              iter = niter, niter = str_list_next(new_list, niter)) {
          char *new_file = (char *)iter->data;
          pkg_t *owner = file_hash_get_file_owner(new_file);
-         if (!new_file)
-              opkg_msg(ERROR, "Null new_file for new_pkg=%s\n", new_pkg->name);
-         if (!owner || (owner == old_pkg))
+         pkg_t *obs = hash_table_get(&conf->obs_file_hash, new_file);
+
+         opkg_msg(DEBUG2, "%s: new_pkg=%s wants file %s, from owner=%s\n",
+               __func__, new_pkg->name, new_file, owner?owner->name:"<NULL>");
+
+         if (!owner || (owner == old_pkg) || obs)
               file_hash_set_file_owner(new_file, new_pkg);
      }
 
               file_hash_set_file_owner(new_file, new_pkg);
      }
 
@@ -169,12 +173,12 @@ update_file_ownership(pkg_t *new_pkg, pkg_t *old_pkg)
                  return -1;
          }
 
                  return -1;
          }
 
-         for (iter = str_list_first(old_list), niter = str_list_next(old_list, iter); 
-                  iter; 
+         for (iter = str_list_first(old_list), niter = str_list_next(old_list, iter);
+                  iter;
                   iter = niter, niter = str_list_next(old_list, niter)) {
               char *old_file = (char *)iter->data;
               pkg_t *owner = file_hash_get_file_owner(old_file);
                   iter = niter, niter = str_list_next(old_list, niter)) {
               char *old_file = (char *)iter->data;
               pkg_t *owner = file_hash_get_file_owner(old_file);
-              if (owner == old_pkg) {
+              if (!owner || (owner == old_pkg)) {
                    /* obsolete */
                    hash_table_insert(&conf->obs_file_hash, old_file, old_pkg);
               }
                    /* obsolete */
                    hash_table_insert(&conf->obs_file_hash, old_file, old_pkg);
               }
@@ -189,20 +193,31 @@ static int
 verify_pkg_installable(pkg_t *pkg)
 {
        unsigned long kbs_available, pkg_size_kbs;
 verify_pkg_installable(pkg_t *pkg)
 {
        unsigned long kbs_available, pkg_size_kbs;
-       char *root_dir;
+       char *root_dir = NULL;
+       struct stat s;
 
        if (conf->force_space || pkg->installed_size == 0)
                return 0;
 
 
        if (conf->force_space || pkg->installed_size == 0)
                return 0;
 
-       root_dir = pkg->dest ? pkg->dest->root_dir :
-                                               conf->default_dest->root_dir;
+       if (pkg->dest)
+       {
+               if (!strcmp(pkg->dest->name, "root") && conf->overlay_root
+                   && !stat(conf->overlay_root, &s) && (s.st_mode & S_IFDIR))
+                       root_dir = conf->overlay_root;
+               else
+                       root_dir = pkg->dest->root_dir;
+       }
+
+       if (!root_dir)
+               root_dir = conf->default_dest->root_dir;
+
        kbs_available = get_available_kbytes(root_dir);
 
        pkg_size_kbs = (pkg->installed_size + 1023)/1024;
 
        if (pkg_size_kbs >= kbs_available) {
        kbs_available = get_available_kbytes(root_dir);
 
        pkg_size_kbs = (pkg->installed_size + 1023)/1024;
 
        if (pkg_size_kbs >= kbs_available) {
-               opkg_msg(ERROR, "Only have %dkb available on filesystem %s, "
-                       "pkg %s needs %d\n",
+               opkg_msg(ERROR, "Only have %ldkb available on filesystem %s, "
+                       "pkg %s needs %ld\n",
                        kbs_available, root_dir, pkg->name, pkg_size_kbs);
                return -1;
        }
                        kbs_available, root_dir, pkg->name, pkg_size_kbs);
                return -1;
        }
@@ -247,7 +262,7 @@ unpack_pkg_control_files(pkg_t *pkg)
          free(conffiles_file_name);
          return 0;
      }
          free(conffiles_file_name);
          return 0;
      }
-    
+
      conffiles_file = fopen(conffiles_file_name, "r");
      if (conffiles_file == NULL) {
          opkg_perror(ERROR, "Failed to open %s", conffiles_file_name);
      conffiles_file = fopen(conffiles_file_name, "r");
      if (conffiles_file == NULL) {
          opkg_perror(ERROR, "Failed to open %s", conffiles_file_name);
@@ -259,6 +274,7 @@ unpack_pkg_control_files(pkg_t *pkg)
      while (1) {
          char *cf_name;
          char *cf_name_in_dest;
      while (1) {
          char *cf_name;
          char *cf_name_in_dest;
+         int i;
 
          cf_name = file_read_line_alloc(conffiles_file);
          if (cf_name == NULL) {
 
          cf_name = file_read_line_alloc(conffiles_file);
          if (cf_name == NULL) {
@@ -267,6 +283,12 @@ unpack_pkg_control_files(pkg_t *pkg)
          if (cf_name[0] == '\0') {
               continue;
          }
          if (cf_name[0] == '\0') {
               continue;
          }
+         for (i = strlen(cf_name) - 1;
+              (i >= 0) && (cf_name[i] == ' ' || cf_name[i] == '\t');
+              i--
+         ) {
+              cf_name[i] = '\0';
+         }
 
          /* Prepend dest->root_dir to conffile name.
             Take pains to avoid multiple slashes. */
 
          /* Prepend dest->root_dir to conffile name.
             Take pains to avoid multiple slashes. */
@@ -295,9 +317,9 @@ unpack_pkg_control_files(pkg_t *pkg)
  * which are no longer a dependency in the new (upgraded) pkg.
  */
 static int
  * which are no longer a dependency in the new (upgraded) pkg.
  */
 static int
-pkg_remove_orphan_dependent(pkg_t *pkg, pkg_t *old_pkg) 
+pkg_remove_orphan_dependent(pkg_t *pkg, pkg_t *old_pkg)
 {
 {
-       int i, j, k, l, found;
+       int i, j, k, l, found,r, err = 0;
        int n_deps;
        pkg_t *p;
        struct compound_depend *cd0, *cd1;
        int n_deps;
        pkg_t *p;
        struct compound_depend *cd0, *cd1;
@@ -321,7 +343,7 @@ pkg_remove_orphan_dependent(pkg_t *pkg, pkg_t *old_pkg)
                        found = 0;
 
                        for (k=0; k<count1; k++) {
                        found = 0;
 
                        for (k=0; k<count1; k++) {
-                               cd1 = &pkg->depends[i];
+                               cd1 = &pkg->depends[k];
                                if (cd1->type != DEPEND)
                                        continue;
                                for (l=0; l<cd1->possibility_count; l++) {
                                if (cd1->type != DEPEND)
                                        continue;
                                for (l=0; l<cd1->possibility_count; l++) {
@@ -362,8 +384,10 @@ pkg_remove_orphan_dependent(pkg_t *pkg, pkg_t *old_pkg)
                                 * which we need to ignore during removal. */
                                p->state_flag |= SF_REPLACE;
 
                                 * which we need to ignore during removal. */
                                p->state_flag |= SF_REPLACE;
 
-                               opkg_remove_pkg(p, 0);
-                       } else 
+                               r = opkg_remove_pkg(p, 0);
+                               if (!err)
+                                       err = r;
+                       } else
                                opkg_msg(INFO, "%s was autoinstalled and is "
                                                "still required by %d "
                                                "installed packages.\n",
                                opkg_msg(INFO, "%s was autoinstalled and is "
                                                "still required by %d "
                                                "installed packages.\n",
@@ -372,7 +396,7 @@ pkg_remove_orphan_dependent(pkg_t *pkg, pkg_t *old_pkg)
                }
        }
 
                }
        }
 
-       return 0;
+       return err;
 }
 
 /* returns number of installed replacees */
 }
 
 /* returns number of installed replacees */
@@ -436,7 +460,7 @@ pkg_remove_installed_replacees_unwind(pkg_vec_t *replacees)
 /* compares versions of pkg and old_pkg, returns 0 if OK to proceed with installation of pkg, 1 otherwise */
 static int
 opkg_install_check_downgrade(pkg_t *pkg, pkg_t *old_pkg, int message)
 /* compares versions of pkg and old_pkg, returns 0 if OK to proceed with installation of pkg, 1 otherwise */
 static int
 opkg_install_check_downgrade(pkg_t *pkg, pkg_t *old_pkg, int message)
-{        
+{
      if (old_pkg) {
           char message_out[15];
          char *old_version = pkg_version_str_alloc(old_pkg);
      if (old_pkg) {
           char message_out[15];
          char *old_version = pkg_version_str_alloc(old_pkg);
@@ -445,53 +469,49 @@ opkg_install_check_downgrade(pkg_t *pkg, pkg_t *old_pkg, int message)
          int rc = 0;
 
           memset(message_out,'\x0',15);
          int rc = 0;
 
           memset(message_out,'\x0',15);
-          strncpy (message_out,"Upgrading ",strlen("Upgrading ")); 
+          strncpy (message_out,"Upgrading ",strlen("Upgrading "));
           if ( (conf->force_downgrade==1) && (cmp > 0) ){     /* We've been asked to allow downgrade  and version is precedent */
           if ( (conf->force_downgrade==1) && (cmp > 0) ){     /* We've been asked to allow downgrade  and version is precedent */
-             cmp = -1 ;                                       /* then we force opkg to downgrade */ 
+             cmp = -1 ;                                       /* then we force opkg to downgrade */
              strncpy (message_out,"Downgrading ",strlen("Downgrading "));         /* We need to use a value < 0 because in the 0 case we are asking to */
                                                               /* reinstall, and some check could fail asking the "force-reinstall" option */
              strncpy (message_out,"Downgrading ",strlen("Downgrading "));         /* We need to use a value < 0 because in the 0 case we are asking to */
                                                               /* reinstall, and some check could fail asking the "force-reinstall" option */
-          } 
+          }
 
          if (cmp > 0) {
 
          if (cmp > 0) {
-              opkg_msg(NOTICE,
-                           "Not downgrading package %s on %s from %s to %s.\n",
-                           old_pkg->name, old_pkg->dest->name, old_version, new_version);
+              if(!conf->download_only)
+                  opkg_msg(NOTICE,
+                          "Not downgrading package %s on %s from %s to %s.\n",
+                          old_pkg->name, old_pkg->dest->name, old_version, new_version);
               rc = 1;
          } else if (cmp < 0) {
               rc = 1;
          } else if (cmp < 0) {
-              opkg_msg(NOTICE, "%s%s on %s from %s to %s...\n",
-                           message_out, pkg->name, old_pkg->dest->name, old_version, new_version);
+              if(!conf->download_only)
+                  opkg_msg(NOTICE, "%s%s on %s from %s to %s...\n",
+                          message_out, pkg->name, old_pkg->dest->name, old_version, new_version);
               pkg->dest = old_pkg->dest;
               rc = 0;
          } else /* cmp == 0 */ {
               pkg->dest = old_pkg->dest;
               rc = 0;
          } else /* cmp == 0 */ {
-              if (conf->force_reinstall) {
-                   opkg_msg(NOTICE, "Reinstalling %s (%s) on %s...\n",
-                                pkg->name, new_version, old_pkg->dest->name);
-                   pkg->dest = old_pkg->dest;
-                   rc = 0;
-              } else {
-                   opkg_msg(NOTICE, "%s (%s) already install on %s."
-                                  " Not reinstalling.\n",
-                                pkg->name, new_version, old_pkg->dest->name);
-                   rc = 1;
-              }
-         } 
+               if(!conf->download_only)
+                   opkg_msg(NOTICE, "%s (%s) already install on %s.\n",
+                       pkg->name, new_version, old_pkg->dest->name);
+              rc = 1;
+         }
          free(old_version);
          free(new_version);
          return rc;
      } else {
          free(old_version);
          free(new_version);
          return rc;
      } else {
-      char message_out[15] ;
-      memset(message_out,'\x0',15);
-      if ( message ) 
-          strncpy( message_out,"Upgrading ",strlen("Upgrading ") );
-      else
-          strncpy( message_out,"Installing ",strlen("Installing ") );
-         char *version = pkg_version_str_alloc(pkg);
-      
-         opkg_msg(NOTICE, "%s%s (%s) to %s...\n", message_out,
-                      pkg->name, version, pkg->dest->name);
-         free(version);
-         return 0;
+          char message_out[15] ;
+          memset(message_out,'\x0',15);
+          if ( message )
+               strncpy( message_out,"Upgrading ",strlen("Upgrading ") );
+          else
+               strncpy( message_out,"Installing ",strlen("Installing ") );
+          char *version = pkg_version_str_alloc(pkg);
+
+          if(!conf->download_only)
+               opkg_msg(NOTICE, "%s%s (%s) to %s...\n", message_out,
+                  pkg->name, version, pkg->dest->name);
+          free(version);
      }
      }
+     return 0;
 }
 
 
 }
 
 
@@ -500,7 +520,7 @@ prerm_upgrade_old_pkg(pkg_t *pkg, pkg_t *old_pkg)
 {
      /* DPKG_INCOMPATIBILITY:
        dpkg does some things here that we don't do yet. Do we care?
 {
      /* DPKG_INCOMPATIBILITY:
        dpkg does some things here that we don't do yet. Do we care?
-       
+
        1. If a version of the package is already installed, call
           old-prerm upgrade new-version
        2. If the script runs but exits with a non-zero exit status
        1. If a version of the package is already installed, call
           old-prerm upgrade new-version
        2. If the script runs but exits with a non-zero exit status
@@ -614,7 +634,7 @@ backup_make_backup(const char *file_name)
 {
      int err;
      char *backup;
 {
      int err;
      char *backup;
-    
+
      backup = backup_filename_alloc(file_name);
      err = file_copy(file_name, backup);
      if (err) {
      backup = backup_filename_alloc(file_name);
      err = file_copy(file_name, backup);
      if (err) {
@@ -667,7 +687,7 @@ backup_modified_conffiles(pkg_t *pkg, pkg_t *old_pkg)
      if (old_pkg) {
          for (iter = nv_pair_list_first(&old_pkg->conffiles); iter; iter = nv_pair_list_next(&old_pkg->conffiles, iter)) {
               char *cf_name;
      if (old_pkg) {
          for (iter = nv_pair_list_first(&old_pkg->conffiles); iter; iter = nv_pair_list_next(&old_pkg->conffiles, iter)) {
               char *cf_name;
-              
+
               cf = iter->data;
               cf_name = root_filename_alloc(cf->name);
 
               cf = iter->data;
               cf_name = root_filename_alloc(cf->name);
 
@@ -733,7 +753,7 @@ check_data_file_clashes(pkg_t *pkg, pkg_t *old_pkg)
        can unwind if necessary).  To avoid complexity and redundant
        storage, opkg doesn't do any installation until later, (at the
        point at which dpkg removes the backups.
        can unwind if necessary).  To avoid complexity and redundant
        storage, opkg doesn't do any installation until later, (at the
        point at which dpkg removes the backups.
-       
+
        But, we do have to check for data file clashes, since after
        installing a package with a file clash, removing either of the
        packages involved in the clash has the potential to break the
        But, we do have to check for data file clashes, since after
        installing a package with a file clash, removing either of the
        packages involved in the clash has the potential to break the
@@ -741,28 +761,26 @@ check_data_file_clashes(pkg_t *pkg, pkg_t *old_pkg)
      */
      str_list_t *files_list;
      str_list_elt_t *iter, *niter;
      */
      str_list_t *files_list;
      str_list_elt_t *iter, *niter;
-
+     char *filename;
      int clashes = 0;
 
      files_list = pkg_get_installed_files(pkg);
      if (files_list == NULL)
             return -1;
 
      int clashes = 0;
 
      files_list = pkg_get_installed_files(pkg);
      if (files_list == NULL)
             return -1;
 
-     for (iter = str_list_first(files_list), niter = str_list_next(files_list, iter); 
-             iter; 
+     for (iter = str_list_first(files_list), niter = str_list_next(files_list, iter);
+             iter;
              iter = niter, niter = str_list_next(files_list, iter)) {
              iter = niter, niter = str_list_next(files_list, iter)) {
-         char *root_filename;
-         char *filename = (char *) iter->data;
-         root_filename = root_filename_alloc(filename);
-         if (file_exists(root_filename) && (! file_is_dir(root_filename))) {
+         filename = (char *) iter->data;
+         if (file_exists(filename) && (! file_is_dir(filename))) {
               pkg_t *owner;
               pkg_t *obs;
 
               pkg_t *owner;
               pkg_t *obs;
 
-              if (backup_exists_for(root_filename)) {
+              if (backup_exists_for(filename)) {
                    continue;
               }
 
                    continue;
               }
 
-              /* Pre-existing files are OK if force-overwrite was asserted. */ 
+              /* Pre-existing files are OK if force-overwrite was asserted. */
               if (conf->force_overwrite) {
                    /* but we need to change who owns this file */
                    file_hash_set_file_owner(filename, pkg);
               if (conf->force_overwrite) {
                    /* but we need to change who owns this file */
                    file_hash_set_file_owner(filename, pkg);
@@ -809,14 +827,13 @@ check_data_file_clashes(pkg_t *pkg, pkg_t *old_pkg)
                            "\tBut that file is already provided by package ",
                            pkg->name, filename);
               if (owner) {
                            "\tBut that file is already provided by package ",
                            pkg->name, filename);
               if (owner) {
-                   opkg_msg(ERROR, "%s\n", owner->name);
+                   opkg_message(ERROR, "%s\n", owner->name);
               } else {
               } else {
-                   opkg_msg(ERROR, "<no package>\n"
+                   opkg_message(ERROR, "<no package>\n"
                        "Please move this file out of the way and try again.\n");
               }
               clashes++;
          }
                        "Please move this file out of the way and try again.\n");
               }
               clashes++;
          }
-         free(root_filename);
      }
      pkg_free_installed_files(pkg);
 
      }
      pkg_free_installed_files(pkg);
 
@@ -846,8 +863,8 @@ check_data_file_clashes_change(pkg_t *pkg, pkg_t *old_pkg)
      if (files_list == NULL)
             return -1;
 
      if (files_list == NULL)
             return -1;
 
-     for (iter = str_list_first(files_list), niter = str_list_next(files_list, iter); 
-             iter; 
+     for (iter = str_list_first(files_list), niter = str_list_next(files_list, iter);
+             iter;
              iter = niter, niter = str_list_next(files_list, niter)) {
          char *filename = (char *) iter->data;
           if (root_filename) {
              iter = niter, niter = str_list_next(files_list, niter)) {
          char *filename = (char *) iter->data;
           if (root_filename) {
@@ -870,7 +887,7 @@ check_data_file_clashes_change(pkg_t *pkg, pkg_t *old_pkg)
               /* Pre-existing files are OK if owned by a package replaced by new pkg. */
               if (owner) {
                    if (pkg_replaces(pkg, owner)) {
               /* Pre-existing files are OK if owned by a package replaced by new pkg. */
               if (owner) {
                    if (pkg_replaces(pkg, owner)) {
-/* It's now time to change the owner of that file. 
+/* It's now time to change the owner of that file.
    It has been "replaced" from the new "Replaces", then I need to inform lists file about that.  */
                         opkg_msg(INFO, "Replacing pre-existing file %s "
                                         "owned by package %s\n",
    It has been "replaced" from the new "Replaces", then I need to inform lists file about that.  */
                         opkg_msg(INFO, "Replacing pre-existing file %s "
                                         "owned by package %s\n",
@@ -924,7 +941,7 @@ postrm_upgrade_old_pkg_unwind(pkg_t *pkg, pkg_t *old_pkg)
 static int
 remove_obsolesced_files(pkg_t *pkg, pkg_t *old_pkg)
 {
 static int
 remove_obsolesced_files(pkg_t *pkg, pkg_t *old_pkg)
 {
-     int err;
+     int err = 0;
      str_list_t *old_files;
      str_list_elt_t *of;
      str_list_t *new_files;
      str_list_t *old_files;
      str_list_elt_t *of;
      str_list_t *new_files;
@@ -964,9 +981,9 @@ remove_obsolesced_files(pkg_t *pkg, pkg_t *old_pkg)
               /* in case obsolete file no longer belongs to old_pkg */
               continue;
          }
               /* in case obsolete file no longer belongs to old_pkg */
               continue;
          }
+
          /* old file is obsolete */
          /* old file is obsolete */
-         opkg_msg(INFO, "Removing obsolete file %s.\n", old);
+         opkg_msg(NOTICE, "Removing obsolete file %s.\n", old);
          if (!conf->noaction) {
               err = unlink(old);
               if (err) {
          if (!conf->noaction) {
               err = unlink(old);
               if (err) {
@@ -979,7 +996,7 @@ remove_obsolesced_files(pkg_t *pkg, pkg_t *old_pkg)
      pkg_free_installed_files(old_pkg);
      pkg_free_installed_files(pkg);
 
      pkg_free_installed_files(old_pkg);
      pkg_free_installed_files(pkg);
 
-     return 0;
+     return err;
 }
 
 static int
 }
 
 static int
@@ -1002,7 +1019,7 @@ remove_disappeared(pkg_t *pkg)
      /* DPKG_INCOMPATIBILITY:
        This is a fairly sophisticated dpkg operation. Shall we
        skip it? */
      /* DPKG_INCOMPATIBILITY:
        This is a fairly sophisticated dpkg operation. Shall we
        skip it? */
-     
+
      /* Any packages all of whose files have been overwritten during the
        installation, and which aren't required for dependencies, are
        considered to have been removed. For each such package
      /* Any packages all of whose files have been overwritten during the
        installation, and which aren't required for dependencies, are
        considered to have been removed. For each such package
@@ -1026,7 +1043,7 @@ install_data_files(pkg_t *pkg)
        than dpkg. Rather than removing backups at this point, we
        actually do the data file installation now. See comments in
        check_data_file_clashes() for more details. */
        than dpkg. Rather than removing backups at this point, we
        actually do the data file installation now. See comments in
        check_data_file_clashes() for more details. */
-    
+
      opkg_msg(INFO, "Extracting data files to %s.\n", pkg->dest->root_dir);
      err = pkg_extract_data_files_to_dir(pkg, pkg->dest->root_dir);
      if (err) {
      opkg_msg(INFO, "Extracting data files to %s.\n", pkg->dest->root_dir);
      err = pkg_extract_data_files_to_dir(pkg, pkg->dest->root_dir);
      if (err) {
@@ -1039,7 +1056,7 @@ install_data_files(pkg_t *pkg)
       * XXX: This should be fixed outside of opkg, in the Package list.
       */
      set_flags_from_control(pkg) ;
       * XXX: This should be fixed outside of opkg, in the Package list.
       */
      set_flags_from_control(pkg) ;
-     
+
      opkg_msg(DEBUG, "Calling pkg_write_filelist.\n");
      err = pkg_write_filelist(pkg);
      if (err)
      opkg_msg(DEBUG, "Calling pkg_write_filelist.\n");
      err = pkg_write_filelist(pkg);
      if (err)
@@ -1096,7 +1113,7 @@ resolve_conffiles(pkg_t *pkg)
                   } else {
                       char *new_conffile;
                       sprintf_alloc(&new_conffile, "%s-opkg", root_filename);
                   } else {
                       char *new_conffile;
                       sprintf_alloc(&new_conffile, "%s-opkg", root_filename);
-                      opkg_msg(NOTICE, "Existing conffile %s "
+                      opkg_msg(ERROR, "Existing conffile %s "
                            "is different from the conffile in the new package."
                            " The new conffile will be placed at %s.\n",
                            root_filename, new_conffile);
                            "is different from the conffile in the new package."
                            " The new conffile will be placed at %s.\n",
                            root_filename, new_conffile);
@@ -1129,15 +1146,17 @@ opkg_install_by_name(const char *pkg_name)
      if (old)
         opkg_msg(DEBUG2, "Old versions from pkg_hash_fetch %s.\n",
                        old->version);
      if (old)
         opkg_msg(DEBUG2, "Old versions from pkg_hash_fetch %s.\n",
                        old->version);
-    
+
      new = pkg_hash_fetch_best_installation_candidate_by_name(pkg_name);
      new = pkg_hash_fetch_best_installation_candidate_by_name(pkg_name);
-     if (new == NULL)
+     if (new == NULL) {
+       opkg_msg(NOTICE, "Unknown package '%s'.\n", pkg_name);
        return -1;
        return -1;
+     }
 
      opkg_msg(DEBUG2, "Versions from pkg_hash_fetch:");
 
      opkg_msg(DEBUG2, "Versions from pkg_hash_fetch:");
-     if ( old ) 
-        opkg_msg(DEBUG2, " old %s ", old->version);
-     opkg_msg(DEBUG2, " new %s\n", new->version);
+     if ( old )
+        opkg_message(DEBUG2, " old %s ", old->version);
+     opkg_message(DEBUG2, " new %s\n", new->version);
 
      new->state_flag |= SF_USER;
      if (old) {
 
      new->state_flag |= SF_USER;
      if (old) {
@@ -1147,16 +1166,16 @@ opkg_install_by_name(const char *pkg_name)
          cmp = pkg_compare_versions(old, new);
           if ( (conf->force_downgrade==1) && (cmp > 0) ){     /* We've been asked to allow downgrade  and version is precedent */
             opkg_msg(DEBUG, "Forcing downgrade\n");
          cmp = pkg_compare_versions(old, new);
           if ( (conf->force_downgrade==1) && (cmp > 0) ){     /* We've been asked to allow downgrade  and version is precedent */
             opkg_msg(DEBUG, "Forcing downgrade\n");
-             cmp = -1 ;                                       /* then we force opkg to downgrade */ 
+             cmp = -1 ;                                       /* then we force opkg to downgrade */
                                                               /* We need to use a value < 0 because in the 0 case we are asking to */
                                                               /* reinstall, and some check could fail asking the "force-reinstall" option */
                                                               /* We need to use a value < 0 because in the 0 case we are asking to */
                                                               /* reinstall, and some check could fail asking the "force-reinstall" option */
-          } 
+          }
          opkg_msg(DEBUG, "Comparing visible versions of pkg %s:"
                       "\n\t%s is installed "
                       "\n\t%s is available "
                       "\n\t%d was comparison result\n",
                       pkg_name, old_version, new_version, cmp);
          opkg_msg(DEBUG, "Comparing visible versions of pkg %s:"
                       "\n\t%s is installed "
                       "\n\t%s is available "
                       "\n\t%d was comparison result\n",
                       pkg_name, old_version, new_version, cmp);
-         if (cmp == 0 && !conf->force_reinstall) {
+         if (cmp == 0) {
               opkg_msg(NOTICE,
                            "Package %s (%s) installed in %s is up to date.\n",
                            old->name, old_version, old->dest->name);
               opkg_msg(NOTICE,
                            "Package %s (%s) installed in %s is up to date.\n",
                            old->name, old_version, old->dest->name);
@@ -1172,7 +1191,7 @@ opkg_install_by_name(const char *pkg_name)
               return 0;
          } else if (cmp < 0) {
               new->dest = old->dest;
               return 0;
          } else if (cmp < 0) {
               new->dest = old->dest;
-              old->state_want = SW_DEINSTALL;    /* Here probably the problem for bug 1277 */
+              old->state_want = SW_DEINSTALL;
          }
          free(old_version);
          free(new_version);
          }
          free(old_version);
          free(new_version);
@@ -1183,7 +1202,7 @@ opkg_install_by_name(const char *pkg_name)
 }
 
 /**
 }
 
 /**
- *  @brief Really install a pkg_t 
+ *  @brief Really install a pkg_t
  */
 int
 opkg_install_pkg(pkg_t *pkg, int from_upgrade)
  */
 int
 opkg_install_pkg(pkg_t *pkg, int from_upgrade)
@@ -1200,7 +1219,7 @@ opkg_install_pkg(pkg_t *pkg, int from_upgrade)
 #endif
      sigset_t newset, oldset;
 
 #endif
      sigset_t newset, oldset;
 
-     if ( from_upgrade ) 
+     if ( from_upgrade )
         message = 1;            /* Coming from an upgrade, and should change the output message */
 
      opkg_msg(DEBUG2, "Calling pkg_arch_supported.\n");
         message = 1;            /* Coming from an upgrade, and should change the output message */
 
      opkg_msg(DEBUG2, "Calling pkg_arch_supported.\n");
@@ -1210,12 +1229,12 @@ opkg_install_pkg(pkg_t *pkg, int from_upgrade)
                       pkg->architecture, pkg->name);
          return -1;
      }
                       pkg->architecture, pkg->name);
          return -1;
      }
-     if (pkg->state_status == SS_INSTALLED && conf->force_reinstall == 0 && conf->nodeps == 0) {
+     if (pkg->state_status == SS_INSTALLED && conf->nodeps == 0) {
          err = satisfy_dependencies_for(pkg);
          if (err)
                  return -1;
 
          err = satisfy_dependencies_for(pkg);
          if (err)
                  return -1;
 
-         opkg_msg(NOTICE, "Package %s is already installed on %s.\n", 
+         opkg_msg(NOTICE, "Package %s is already installed on %s.\n",
                       pkg->name, pkg->dest->name);
          return 0;
      }
                       pkg->name, pkg->dest->name);
          return 0;
      }
@@ -1231,27 +1250,35 @@ opkg_install_pkg(pkg_t *pkg, int from_upgrade)
             return -1;
 
      pkg->state_want = SW_INSTALL;
             return -1;
 
      pkg->state_want = SW_INSTALL;
-     if (old_pkg){                          
-         old_pkg->state_want = SW_DEINSTALL; /* needed for check_data_file_clashes of dependences */
+     if (old_pkg){
+         old_pkg->state_want = SW_DEINSTALL; /* needed for check_data_file_clashes of dependencies */
      }
 
      err = check_conflicts_for(pkg);
      if (err)
             return -1;
      }
 
      err = check_conflicts_for(pkg);
      if (err)
             return -1;
-    
+
      /* this setup is to remove the upgrade scenario in the end when
        installing pkg A, A deps B & B deps on A. So both B and A are
        installed. Then A's installation is started resulting in an
      /* this setup is to remove the upgrade scenario in the end when
        installing pkg A, A deps B & B deps on A. So both B and A are
        installed. Then A's installation is started resulting in an
-       uncecessary upgrade */ 
-     if (pkg->state_status == SS_INSTALLED && conf->force_reinstall == 0)
+       uncecessary upgrade */
+     if (pkg->state_status == SS_INSTALLED)
             return 0;
             return 0;
-    
+
      err = verify_pkg_installable(pkg);
      if (err)
             return -1;
 
      if (pkg->local_filename == NULL) {
      err = verify_pkg_installable(pkg);
      if (err)
             return -1;
 
      if (pkg->local_filename == NULL) {
-         err = opkg_download_pkg(pkg, conf->tmp_dir);
+         if(!conf->cache && conf->download_only){
+             char cwd[4096];
+             if(getcwd(cwd, sizeof(cwd)) != NULL)
+                err = opkg_download_pkg(pkg, cwd);
+             else
+                return -1;
+         } else {
+             err = opkg_download_pkg(pkg, conf->tmp_dir);
+         }
          if (err) {
               opkg_msg(ERROR, "Failed to download %s. "
                               "Perhaps you need to run 'opkg update'?\n",
          if (err) {
               opkg_msg(ERROR, "Failed to download %s. "
                               "Perhaps you need to run 'opkg update'?\n",
@@ -1300,12 +1327,19 @@ opkg_install_pkg(pkg_t *pkg, int from_upgrade)
          file_md5 = file_md5sum_alloc(pkg->local_filename);
          if (file_md5 && strcmp(file_md5, pkg->md5sum))
          {
          file_md5 = file_md5sum_alloc(pkg->local_filename);
          if (file_md5 && strcmp(file_md5, pkg->md5sum))
          {
-              opkg_msg(ERROR, "Package %s md5sum mismatch. "
-                       "Either the opkg or the package index are corrupt. "
-                       "Try 'opkg update'.\n",
-                       pkg->name);
-              free(file_md5);
-              return -1;
+              if (!conf->force_checksum)
+              {
+                  opkg_msg(ERROR, "Package %s md5sum mismatch. "
+                           "Either the opkg or the package index are corrupt. "
+                           "Try 'opkg update'.\n",
+                           pkg->name);
+                  free(file_md5);
+                  return -1;
+              }
+              else
+              {
+                  opkg_msg(NOTICE, "Ignored %s md5sum mismatch.\n", pkg->name);
+              }
          }
         if (file_md5)
               free(file_md5);
          }
         if (file_md5)
               free(file_md5);
@@ -1329,6 +1363,14 @@ opkg_install_pkg(pkg_t *pkg, int from_upgrade)
               free(file_sha256);
      }
 #endif
               free(file_sha256);
      }
 #endif
+     if(conf->download_only) {
+         if (conf->nodeps == 0) {
+             err = satisfy_dependencies_for(pkg);
+             if (err)
+                 return -1;
+         }
+         return 0;
+     }
 
      if (pkg->tmp_unpack_dir == NULL) {
          if (unpack_pkg_control_files(pkg) == -1) {
 
      if (pkg->tmp_unpack_dir == NULL) {
          if (unpack_pkg_control_files(pkg) == -1) {
@@ -1367,7 +1409,7 @@ opkg_install_pkg(pkg_t *pkg, int from_upgrade)
                pkg_remove_orphan_dependent(pkg, old_pkg);
 
          /* XXX: BUG: we really should treat replacement more like an upgrade
                pkg_remove_orphan_dependent(pkg, old_pkg);
 
          /* XXX: BUG: we really should treat replacement more like an upgrade
-          *      Instead, we're going to remove the replacees 
+          *      Instead, we're going to remove the replacees
           */
          err = pkg_remove_installed_replacees(replacees);
          if (err)
           */
          err = pkg_remove_installed_replacees(replacees);
          if (err)
@@ -1401,7 +1443,7 @@ opkg_install_pkg(pkg_t *pkg, int from_upgrade)
                  return 0;
 
          /* point of no return: no unwinding after this */
                  return 0;
 
          /* point of no return: no unwinding after this */
-         if (old_pkg && !conf->force_reinstall) {
+         if (old_pkg) {
               old_pkg->state_want = SW_DEINSTALL;
 
               if (old_pkg->state_flag & SF_NOPRUNE) {
               old_pkg->state_want = SW_DEINSTALL;
 
               if (old_pkg->state_flag & SF_NOPRUNE) {
@@ -1418,7 +1460,7 @@ opkg_install_pkg(pkg_t *pkg, int from_upgrade)
                    }
               }
 
                    }
               }
 
-               /* removing files from old package, to avoid ghost files */ 
+               /* removing files from old package, to avoid ghost files */
                remove_data_files_and_list(old_pkg);
                remove_maintainer_scripts(old_pkg);
          }
                remove_data_files_and_list(old_pkg);
                remove_maintainer_scripts(old_pkg);
          }
@@ -1460,9 +1502,8 @@ opkg_install_pkg(pkg_t *pkg, int from_upgrade)
          opkg_msg(DEBUG, "pkg=%s old_state_flag=%x state_flag=%x\n",
                          pkg->name, old_state_flag, pkg->state_flag);
 
          opkg_msg(DEBUG, "pkg=%s old_state_flag=%x state_flag=%x\n",
                          pkg->name, old_state_flag, pkg->state_flag);
 
-         if (old_pkg && !conf->force_reinstall) {
+         if (old_pkg)
               old_pkg->state_status = SS_NOT_INSTALLED;
               old_pkg->state_status = SS_NOT_INSTALLED;
-         }
 
          time(&pkg->installed_time);
 
 
          time(&pkg->installed_time);
 
@@ -1473,7 +1514,7 @@ opkg_install_pkg(pkg_t *pkg, int from_upgrade)
          sigprocmask(SIG_UNBLOCK, &newset, &oldset);
           pkg_vec_free (replacees);
          return 0;
          sigprocmask(SIG_UNBLOCK, &newset, &oldset);
           pkg_vec_free (replacees);
          return 0;
-     
+
 
      UNWIND_POSTRM_UPGRADE_OLD_PKG:
          postrm_upgrade_old_pkg_unwind(pkg, old_pkg);
 
      UNWIND_POSTRM_UPGRADE_OLD_PKG:
          postrm_upgrade_old_pkg_unwind(pkg, old_pkg);