Provide a more useful comment.
[oweals/opkg-lede.git] / libopkg / opkg_install.c
index 4a1ff9ac441cd7dd402145af1f0e2446d5c23640..3ee72424ed1de8c35c0b46e67142920dcc9ea77b 100644 (file)
@@ -69,8 +69,6 @@ static int remove_disappeared(opkg_conf_t *conf, pkg_t *pkg);
 static int install_data_files(opkg_conf_t *conf, pkg_t *pkg);
 static int resolve_conffiles(opkg_conf_t *conf, pkg_t *pkg);
 
-static int cleanup_temporary_files(opkg_conf_t *conf, pkg_t *pkg);
-
 static int user_prefers_old_conffile(const char *file, const char *backup);
 
 static char *backup_filename_alloc(const char *file_name);
@@ -87,7 +85,7 @@ int opkg_install_from_file(opkg_conf_t *conf, const char *filename)
 
      pkg = pkg_new();
 
-     err = pkg_init_from_file(pkg, filename);
+     err = pkg_init_from_file(conf, pkg, filename);
      if (err) {
          return err;
      }
@@ -204,6 +202,8 @@ opkg_error_t opkg_install_by_name(opkg_conf_t *conf, const char *pkg_name)
               new->dest = old->dest;
               old->state_want = SW_DEINSTALL;    /* Here probably the problem for bug 1277 */
          }
+         free(old_version);
+         free(new_version);
      }
 
      /* XXX: CLEANUP: The error code of opkg_install_by_name is really
@@ -427,7 +427,7 @@ static int check_conflicts_for(opkg_conf_t *conf, pkg_t *pkg)
 
 static int update_file_ownership(opkg_conf_t *conf, pkg_t *new_pkg, pkg_t *old_pkg)
 {
-     str_list_t *new_list = pkg_get_installed_files(new_pkg);
+     str_list_t *new_list = pkg_get_installed_files(conf, new_pkg);
      str_list_elt_t *iter, *niter;
 
      for (iter = str_list_first(new_list), niter = str_list_next(new_list, iter); 
@@ -441,7 +441,7 @@ static int update_file_ownership(opkg_conf_t *conf, pkg_t *new_pkg, pkg_t *old_p
               file_hash_set_file_owner(conf, new_file, new_pkg);
      }
      if (old_pkg) {
-         str_list_t *old_list = pkg_get_installed_files(old_pkg);
+         str_list_t *old_list = pkg_get_installed_files(conf, old_pkg);
          for (iter = str_list_first(old_list), niter = str_list_next(old_list, iter); 
                   iter; 
                   iter = niter, niter = str_list_next(old_list, niter)) {
@@ -573,56 +573,92 @@ static int unpack_pkg_control_files(opkg_conf_t *conf, pkg_t *pkg)
      return 0;
 }
 
-static int pkg_remove_orphan_dependent(opkg_conf_t *conf, pkg_t *pkg, pkg_t *old_pkg) 
+/*
+ * Remove packages which were auto_installed due to a dependency by old_pkg,
+ * which are no longer a dependency in the new (upgraded) pkg.
+ */
+static int
+pkg_remove_orphan_dependent(opkg_conf_t *conf, pkg_t *pkg, pkg_t *old_pkg) 
 {
-    int i, j, found;
-    char *buf, *d_str;
-    pkg_t *p;
-
-    if (!old_pkg) 
-        return 0;
-
-    if (old_pkg->depends_count == 0) 
-        return 0;
-
-    for (i=0;i<old_pkg->depends_count;i++) {
-        found = 0;
-        for (j=0;j<pkg->depends_count;j++) {
-            if (!strcmp(old_pkg->depends_str[i], pkg->depends_str[j])) {
-                found = 1;
-                break;
-            }
-        }
-        if (found)
-            continue;
-        d_str = old_pkg->depends_str[i];
-        buf = xcalloc(1, strlen (d_str) + 1);
-        j=0;
-        while (d_str[j] != '\0' && d_str[j] != ' ') {
-            buf[j]=d_str[j];
-            ++j;
-        }
-        buf[j]='\0';
-        buf = xrealloc (buf, strlen (buf) + 1);
-        p = pkg_hash_fetch_installed_by_name (&conf->pkg_hash, buf);
-        if (!p) {
-            fprintf(stderr, "The pkg %s had been removed!!\n", buf);
-            free(buf);
-            continue;
-        }
-        if (p->auto_installed) {
-            int deps;
-            abstract_pkg_t **dependents;
-            deps = pkg_has_installed_dependents(conf, NULL, p, &dependents);
-            if (deps == 0) {
-                opkg_message (conf, OPKG_NOTICE,"%s was autoinstalled but is now orphaned, remove it.\n", buf);
-                opkg_remove_pkg(conf, p, 0);
-            } else 
-                opkg_message (conf, OPKG_INFO, "%s was autoinstalled and is still required by %d installed packages\n", buf, deps);
-        }
-        free(buf);
-    }
-    return 0;
+       int i, j, k, l, found;
+       int n_deps;
+       pkg_t *p;
+       struct compound_depend *cd0, *cd1;
+        abstract_pkg_t **dependents;
+
+       int count0 = old_pkg->pre_depends_count +
+                               old_pkg->depends_count +
+                               old_pkg->recommends_count +
+                               old_pkg->suggests_count;
+       int count1 = pkg->pre_depends_count +
+                               pkg->depends_count +
+                               pkg->recommends_count +
+                               pkg->suggests_count;
+
+       for (i=0; i<count0; i++) {
+               cd0 = &old_pkg->depends[i];
+               if (cd0->type != DEPEND)
+                       continue;
+               for (j=0; j<cd0->possibility_count; j++) {
+
+                       found = 0;
+
+                       for (k=0; k<count1; k++) {
+                               cd1 = &pkg->depends[i];
+                               if (cd1->type != DEPEND)
+                                       continue;
+                               for (l=0; l<cd1->possibility_count; l++) {
+                                       if (cd0->possibilities[j]
+                                        == cd1->possibilities[l]) {
+                                               found = 1;
+                                               break;
+                                       }
+                               }
+                               if (found)
+                                       break;
+                       }
+
+                       if (found)
+                               continue;
+
+                       /*
+                        * old_pkg has a dependency that pkg does not.
+                        */
+                       p = pkg_hash_fetch_installed_by_name (&conf->pkg_hash,
+                                       cd0->possibilities[j]->pkg->name);
+
+                       if (!p)
+                               continue;
+
+                       if (!p->auto_installed)
+                               continue;
+
+                       n_deps = pkg_has_installed_dependents(conf, NULL, p,
+                                       &dependents);
+                       n_deps--; /* don't count old_pkg */
+
+                       if (n_deps == 0) {
+                               opkg_message (conf, OPKG_NOTICE,
+                                               "%s was autoinstalled and is "
+                                               "now orphaned, removing.\n",
+                                               p->name);
+
+                               /* p has one installed dependency (old_pkg),
+                                * which we need to ignore during removal. */
+                               p->state_flag |= SF_REPLACE;
+
+                               opkg_remove_pkg(conf, p, 0);
+                       } else 
+                               opkg_message(conf, OPKG_INFO,
+                                               "%s was autoinstalled and is "
+                                               "still required by %d "
+                                               "installed packages.\n",
+                                               p->name, n_deps);
+
+               }
+       }
+
+       return 0;
 }
 
 /* returns number of installed replacees */
@@ -680,12 +716,6 @@ int pkg_remove_installed_replacees_unwind(opkg_conf_t *conf, pkg_vec_t *replacee
      return 0;
 }
 
-int caught_sigint = 0;
-static void opkg_install_pkg_sigint_handler(int sig)
-{
-     caught_sigint = sig;
-}
-
 /* 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(opkg_conf_t *conf, pkg_t *pkg, pkg_t *old_pkg, int message)
 {        
@@ -910,6 +940,9 @@ int opkg_install_pkg(opkg_conf_t *conf, pkg_t *pkg, int from_upgrade)
      if (conf->nodeps == 0) {
          err = satisfy_dependencies_for(conf, pkg);
          if (err) { return OPKG_INSTALL_ERR_DEPENDENCIES; }
+          if (pkg->state_status == SS_UNPACKED)
+               /* Circular dependency has installed it for us. */
+               return 0;
      }
 
      replacees = pkg_vec_alloc();
@@ -918,21 +951,16 @@ int opkg_install_pkg(opkg_conf_t *conf, pkg_t *pkg, int from_upgrade)
      /* this next section we do with SIGINT blocked to prevent inconsistency between opkg database and filesystem */
      {
          sigset_t newset, oldset;
-         sighandler_t old_handler = NULL;
-         int use_signal = 0;
-         caught_sigint = 0;
-         if (use_signal) {
-              old_handler = signal(SIGINT, opkg_install_pkg_sigint_handler);
-         } else {
-              sigemptyset(&newset);
-              sigaddset(&newset, SIGINT);
-              sigprocmask(SIG_BLOCK, &newset, &oldset);
-         }
+
+         sigemptyset(&newset);
+         sigaddset(&newset, SIGINT);
+         sigprocmask(SIG_BLOCK, &newset, &oldset);
 
          opkg_state_changed++;
          pkg->state_flag |= SF_FILELIST_CHANGED;
 
-          pkg_remove_orphan_dependent(conf, pkg, old_pkg);
+         if (old_pkg)
+               pkg_remove_orphan_dependent(conf, pkg, old_pkg);
 
          /* XXX: BUG: we really should treat replacement more like an upgrade
           *      Instead, we're going to remove the replacees 
@@ -1011,20 +1039,13 @@ int opkg_install_pkg(opkg_conf_t *conf, pkg_t *pkg, int from_upgrade)
 
          time(&pkg->installed_time);
 
-         opkg_message(conf, OPKG_INFO,
-                      "  cleanup temp files\n");
-         cleanup_temporary_files(conf, pkg);
-
          ab_pkg = pkg->parent;
          if (ab_pkg)
               ab_pkg->state_status = pkg->state_status;
 
          opkg_message(conf, OPKG_INFO, "Done.\n");
 
-         if (use_signal)
-              signal(SIGINT, old_handler);
-         else
-              sigprocmask(SIG_UNBLOCK, &newset, &oldset);
+         sigprocmask(SIG_UNBLOCK, &newset, &oldset);
           pkg_vec_free (replacees);
          return 0;
      
@@ -1044,16 +1065,10 @@ int opkg_install_pkg(opkg_conf_t *conf, pkg_t *pkg, int from_upgrade)
      UNWIND_REMOVE_INSTALLED_REPLACEES:
          pkg_remove_installed_replacees_unwind(conf, replacees);
 
-         opkg_message(conf, OPKG_INFO,
-                      "  cleanup temp files\n");
-         cleanup_temporary_files(conf, pkg);
-
          opkg_message(conf, OPKG_INFO,
                       "Failed.\n");
-         if (use_signal)
-              signal(SIGINT, old_handler);
-         else
-              sigprocmask(SIG_UNBLOCK, &newset, &oldset);
+
+         sigprocmask(SIG_UNBLOCK, &newset, &oldset);
 
           pkg_vec_free (replacees);
          return OPKG_ERR_UNKNOWN;
@@ -1245,7 +1260,7 @@ static int check_data_file_clashes(opkg_conf_t *conf, pkg_t *pkg, pkg_t *old_pkg
 
      int clashes = 0;
 
-     files_list = pkg_get_installed_files(pkg);
+     files_list = pkg_get_installed_files(conf, pkg);
      for (iter = str_list_first(files_list), niter = str_list_next(files_list, iter); 
              iter; 
              iter = niter, niter = str_list_next(files_list, iter)) {
@@ -1336,7 +1351,7 @@ static int check_data_file_clashes_change(opkg_conf_t *conf, pkg_t *pkg, pkg_t *
 
      int clashes = 0;
 
-     files_list = pkg_get_installed_files(pkg);
+     files_list = pkg_get_installed_files(conf, pkg);
      for (iter = str_list_first(files_list), niter = str_list_next(files_list, iter); 
              iter; 
              iter = niter, niter = str_list_next(files_list, niter)) {
@@ -1420,8 +1435,8 @@ static int remove_obsolesced_files(opkg_conf_t *conf, pkg_t *pkg, pkg_t *old_pkg
          return 0;
      }
 
-     old_files = pkg_get_installed_files(old_pkg);
-     new_files = pkg_get_installed_files(pkg);
+     old_files = pkg_get_installed_files(conf, old_pkg);
+     new_files = pkg_get_installed_files(conf, pkg);
 
      new_files_table.entries = NULL;
      hash_table_init("new_files" , &new_files_table, 20);
@@ -1582,7 +1597,7 @@ static int resolve_conffiles(opkg_conf_t *conf, pkg_t *pkg)
                   if (conf->force_maintainer) {
                       opkg_message(conf, OPKG_NOTICE, "Conffile %s using maintainer's setting.\n", cf_backup);
                   } else if (conf->force_defaults
-                          || user_prefers_old_conffile(cf->name, cf_backup) ) {
+                          || user_prefers_old_conffile(root_filename, cf_backup) ) {
                       rename(cf_backup, root_filename);
                   }
               }
@@ -1620,6 +1635,10 @@ static int user_prefers_old_conffile(const char *file_name, const char *backup)
                                       "          D     : show the differences between the versions (if diff is installed)\n"
                                       "     The default action is to keep your current version.\n"
                                       "    *** %s (Y/I/N/O/D) [default=N] ? ", file_name, short_file_name);
+
+         if (response == NULL)
+                 return 1;
+
          if (strcmp(response, "y") == 0
              || strcmp(response, "i") == 0
              || strcmp(response, "yes") == 0) {
@@ -1628,13 +1647,8 @@ static int user_prefers_old_conffile(const char *file_name, const char *backup)
          }
 
          if (strcmp(response, "d") == 0) {
-              char *cmd;
-
-              free(response);
-              /* XXX: BUG rewrite to use exec or busybox's internal diff */
-              sprintf_alloc(&cmd, "diff -u %s %s", backup, file_name);
-              xsystem(cmd);
-              free(cmd);
+              const char *argv[] = {"diff", "-u", backup, file_name, NULL};
+              xsystem(argv);
               printf("    [Press ENTER to continue]\n");
               response = file_read_line_alloc(stdin);
               free(response);
@@ -1646,57 +1660,6 @@ static int user_prefers_old_conffile(const char *file_name, const char *backup)
      }
 }
 
-/* XXX: CLEANUP: I'd like to move all of the code for
-   creating/cleaning pkg->tmp_unpack_dir directly into pkg.c. (Then,
-   it would make sense to cleanup pkg->tmp_unpack_dir directly from
-   pkg_deinit for example). */
-static int cleanup_temporary_files(opkg_conf_t *conf, pkg_t *pkg)
-{
-     DIR *tmp_dir;
-     struct dirent *dirent;
-     char *tmp_file;
-
-#ifdef OPKG_DEBUG_NO_TMP_CLEANUP
-#error
-     opkg_message(conf, OPKG_DEBUG,
-                 "%s: Not cleaning up %s since opkg compiled with OPKG_DEBUG_NO_TMP_CLEANUP\n",
-                 __FUNCTION__, pkg->tmp_unpack_dir);
-     return 0;
-#endif
-
-     if (pkg->tmp_unpack_dir && file_is_dir(pkg->tmp_unpack_dir)) {
-         tmp_dir = opendir(pkg->tmp_unpack_dir);
-         if (tmp_dir) {
-              while (1) {
-                   dirent = readdir(tmp_dir);
-                   if (dirent == NULL) {
-                        break;
-                   }
-                   sprintf_alloc(&tmp_file, "%s/%s",
-                                 pkg->tmp_unpack_dir, dirent->d_name);
-                   if (! file_is_dir(tmp_file)) {
-                        unlink(tmp_file);
-                   }
-                   free(tmp_file);
-              }
-              closedir(tmp_dir);
-              rmdir(pkg->tmp_unpack_dir);
-              free(pkg->tmp_unpack_dir);
-              pkg->tmp_unpack_dir = NULL;
-         }
-     }
-
-     opkg_message(conf, OPKG_INFO, "cleanup_temporary_files: pkg=%s local_filename=%s tmp_dir=%s\n",
-                 pkg->name, pkg->local_filename, conf->tmp_dir);
-     if (pkg->local_filename && strncmp(pkg->local_filename, conf->tmp_dir, strlen(conf->tmp_dir)) == 0) {
-         unlink(pkg->local_filename);
-         free(pkg->local_filename);
-         pkg->local_filename = NULL;
-     }
-
-     return 0;
-}
-
 static char *backup_filename_alloc(const char *file_name)
 {
      char *backup;