]> git.saurik.com Git - apt.git/commitdiff
Merge branch 'portability/freebsd'
authorJulian Andres Klode <jak@debian.org>
Fri, 26 Aug 2016 22:31:03 +0000 (00:31 +0200)
committerJulian Andres Klode <jak@debian.org>
Fri, 26 Aug 2016 22:31:03 +0000 (00:31 +0200)
1  2 
apt-pkg/acquire-item.cc
apt-pkg/acquire-worker.cc
apt-pkg/acquire.cc
apt-pkg/deb/dpkgpm.cc
cmdline/apt-key.in
test/integration/framework

diff --combined apt-pkg/acquire-item.cc
index 7fbbf08f81866e24e4ab48c163f730e34fd24765,88b5a58b56896f2dae393fb6acce4289adbbc1ea..91d7a3eaea2e6c3f0b18a82888a462a2424e2147
@@@ -145,7 -145,7 +145,7 @@@ static void ReportMirrorFailureToCentra
             << FailCode << std::endl;
  #endif
     string const report = _config->Find("Methods::Mirror::ProblemReporting",
-                                "/usr/lib/apt/apt-report-mirror-failure");
+                                LIBEXEC_DIR "/apt-report-mirror-failure");
     if(!FileExists(report))
        return;
  
@@@ -2047,7 -2047,7 +2047,7 @@@ bool pkgAcqDiffIndex::ParseDiffIndex(st
     HashStringList ServerHashes;
     unsigned long long ServerSize = 0;
  
-    auto const &posix = std::locale("C.UTF-8");
+    auto const &posix = std::locale::classic();
     for (char const * const * type = HashString::SupportedHashes(); *type != NULL; ++type)
     {
        std::string tagname = *type;
@@@ -3279,8 -3279,9 +3279,8 @@@ bool pkgAcqArchive::QueueNext(
  
        // Create the item
        Local = false;
 -      QueueURI(Desc);
 -
        ++Vf;
 +      QueueURI(Desc);
        return true;
     }
     return false;
@@@ -3439,7 -3440,7 +3439,7 @@@ void pkgAcqChangelog::Init(std::string 
     TemporaryDirectory = tmpname;
  
     ChangeOwnerAndPermissionOfFile("Item::QueueURI", TemporaryDirectory.c_str(),
-        SandboxUser.c_str(), "root", 0700);
+        SandboxUser.c_str(), ROOT_GROUP, 0700);
  
     DestFile = flCombine(TemporaryDirectory, DestFileName);
     if (DestDir.empty() == false)
@@@ -3487,7 -3488,8 +3487,8 @@@ std::string pkgAcqChangelog::URI(pkgCac
        pkgCache::PkgIterator const Pkg = Ver.ParentPkg();
        if (Pkg->CurrentVer != 0 && Pkg.CurrentVer() == Ver)
        {
-        std::string const basename = std::string("/usr/share/doc/") + Pkg.Name() + "/changelog";
+        std::string const root = _config->FindDir("Dir");
+        std::string const basename = root + std::string("usr/share/doc/") + Pkg.Name() + "/changelog";
         std::string const debianname = basename + ".Debian";
         if (FileExists(debianname))
            return "copy://" + debianname;
index 5b6634db82d442e493e5c6956e3e4f508e4f0b1a,7afbec72a243e99e8a020490aa14a776ef3ad7fe..7d6e6f79c2e5b95d520fe7bec49b2219eec6c4aa
@@@ -661,15 -661,55 +661,15 @@@ bool pkgAcquire::Worker::QueueItem(pkgA
     if (OutFd == -1)
        return false;
  
 -   HashStringList const hsl = Item->GetExpectedHashes();
 -
     if (isDoomedItem(Item->Owner))
        return true;
  
 -   if (hsl.usable() == false && Item->Owner->HashesRequired() &&
 -       _config->Exists("Acquire::ForceHash") == false)
 -   {
 -      std::string const Message = "400 URI Failure"
 -       "\nURI: " + Item->URI +
 -       "\nFilename: " + Item->Owner->DestFile +
 -       "\nFailReason: WeakHashSums";
 -
 -      auto const ItmOwners = Item->Owners;
 -      for (auto &O: ItmOwners)
 -      {
 -       O->Status = pkgAcquire::Item::StatAuthError;
 -       O->Failed(Message, Config);
 -       if (Log != nullptr)
 -          Log->Fail(O->GetItemDesc());
 -      }
 -      // "queued" successfully, the item just instantly failed
 -      return true;
 -   }
 -
 -   if (Item->Owner->IsRedirectionLoop(Item->URI))
 -   {
 -      std::string const Message = "400 URI Failure"
 -       "\nURI: " + Item->URI +
 -       "\nFilename: " + Item->Owner->DestFile +
 -       "\nFailReason: RedirectionLoop";
 -
 -      auto const ItmOwners = Item->Owners;
 -      for (auto &O: ItmOwners)
 -      {
 -       O->Status = pkgAcquire::Item::StatError;
 -       O->Failed(Message, Config);
 -       if (Log != nullptr)
 -          Log->Fail(O->GetItemDesc());
 -      }
 -      // "queued" successfully, the item just instantly failed
 -      return true;
 -   }
 -
     string Message = "600 URI Acquire\n";
     Message.reserve(300);
     Message += "URI: " + Item->URI;
     Message += "\nFilename: " + Item->Owner->DestFile;
  
 +   HashStringList const hsl = Item->GetExpectedHashes();
     for (HashStringList::const_iterator hs = hsl.begin(); hs != hsl.end(); ++hs)
        Message += "\nExpected-" + hs->HashType() + ": " + hs->HashValue();
  
     {
        std::string const SandboxUser = _config->Find("APT::Sandbox::User");
        ChangeOwnerAndPermissionOfFile("Item::QueueURI", Item->Owner->DestFile.c_str(),
-                                      SandboxUser.c_str(), "root", 0600);
+                                      SandboxUser.c_str(), ROOT_GROUP, 0600);
     }
  
     if (Debug == true)
@@@ -788,7 -828,7 +788,7 @@@ void pkgAcquire::Worker::PrepareFiles(c
  {
     if (RealFileExists(Itm->Owner->DestFile))
     {
-       ChangeOwnerAndPermissionOfFile(caller, Itm->Owner->DestFile.c_str(), "root", "root", 0644);
+       ChangeOwnerAndPermissionOfFile(caller, Itm->Owner->DestFile.c_str(), "root", ROOT_GROUP, 0644);
        std::string const filename = Itm->Owner->DestFile;
        for (pkgAcquire::Queue::QItem::owner_iterator O = Itm->Owners.begin(); O != Itm->Owners.end(); ++O)
        {
diff --combined apt-pkg/acquire.cc
index e588b0306513f4cd75a73dc50e09c878b9713bb3,b5f88e1b39a6e929105fd77862f449fa1c1e973b..b4d1b595931cf9a32bf4f01d8be19ad49d8de617
@@@ -80,7 -80,7 +80,7 @@@ void pkgAcquire::Initialize(
     if (getuid() == 0 && SandboxUser.empty() == false && SandboxUser != "root") // if we aren't root, we can't chown, so don't try it
     {
        struct passwd const * const pw = getpwnam(SandboxUser.c_str());
-       struct group const * const gr = getgrnam("root");
+       struct group const * const gr = getgrnam(ROOT_GROUP);
        if (pw != NULL && gr != NULL)
        {
         std::string const AuthConf = _config->FindFile("Dir::Etc::netrc");
@@@ -106,7 -106,7 +106,7 @@@ static bool SetupAPTPartialDirectory(st
     if (getuid() == 0 && SandboxUser.empty() == false && SandboxUser != "root") // if we aren't root, we can't chown, so don't try it
     {
        struct passwd const * const pw = getpwnam(SandboxUser.c_str());
-       struct group const * const gr = getgrnam("root");
+       struct group const * const gr = getgrnam(ROOT_GROUP);
        if (pw != NULL && gr != NULL)
        {
           // chown the partial dir
@@@ -269,42 -269,6 +269,42 @@@ void pkgAcquire::Remove(Worker *Work
     it is constructed which creates a queue (based on the current queue
     mode) and puts the item in that queue. If the system is running then
     the queue might be started. */
 +static bool CheckForBadItemAndFailIt(pkgAcquire::Item * const Item,
 +      pkgAcquire::MethodConfig const * const Config, pkgAcquireStatus * const Log)
 +{
 +   auto SavedDesc = Item->GetItemDesc();
 +   if (Item->IsRedirectionLoop(SavedDesc.URI))
 +   {
 +      std::string const Message = "400 URI Failure"
 +       "\nURI: " + SavedDesc.URI +
 +       "\nFilename: " + Item->DestFile +
 +       "\nFailReason: RedirectionLoop";
 +
 +      Item->Status = pkgAcquire::Item::StatError;
 +      Item->Failed(Message, Config);
 +      if (Log != nullptr)
 +       Log->Fail(SavedDesc);
 +      return true;
 +   }
 +
 +   HashStringList const hsl = Item->GetExpectedHashes();
 +   if (hsl.usable() == false && Item->HashesRequired() &&
 +       _config->Exists("Acquire::ForceHash") == false)
 +   {
 +      std::string const Message = "400 URI Failure"
 +       "\nURI: " + SavedDesc.URI +
 +       "\nFilename: " + Item->DestFile +
 +       "\nFailReason: WeakHashSums";
 +
 +      auto SavedDesc = Item->GetItemDesc();
 +      Item->Status = pkgAcquire::Item::StatAuthError;
 +      Item->Failed(Message, Config);
 +      if (Log != nullptr)
 +       Log->Fail(SavedDesc);
 +      return true;
 +   }
 +   return false;
 +}
  void pkgAcquire::Enqueue(ItemDesc &Item)
  {
     // Determine which queue to put the item in
     if (Name.empty() == true)
        return;
  
 +   /* the check for running avoids that we produce errors
 +      in logging before we actually have started, which would
 +      be easier to implement but would confuse users/implementations
 +      so we check the items skipped here in #Startup */
 +   if (Running && CheckForBadItemAndFailIt(Item.Owner, Config, Log))
 +      return;
 +
     // Find the queue structure
     Queue *I = Queues;
     for (; I != 0 && I->Name != Name; I = I->Next);
@@@ -955,20 -912,10 +955,20 @@@ bool pkgAcquire::Queue::Startup(
     if (Workers == 0)
     {
        URI U(Name);
 -      pkgAcquire::MethodConfig *Cnf = Owner->GetConfig(U.Access);
 -      if (Cnf == 0)
 +      pkgAcquire::MethodConfig * const Cnf = Owner->GetConfig(U.Access);
 +      if (unlikely(Cnf == nullptr))
         return false;
 -      
 +
 +      // now-running twin of the pkgAcquire::Enqueue call
 +      for (QItem *I = Items; I != 0; )
 +      {
 +       auto const INext = I->Next;
 +       for (auto &&O: I->Owners)
 +          CheckForBadItemAndFailIt(O, Cnf, Owner->Log);
 +       // if an item failed, it will be auto-dequeued invalidation our I here
 +       I = INext;
 +      }
 +
        Workers = new Worker(this,Cnf,Owner->Log);
        Owner->Add(Workers);
        if (Workers->Start() == false)
@@@ -1312,7 -1259,7 +1312,7 @@@ bool pkgAcquireStatus::Pulse(pkgAcquir
  
        // build the status str
        std::ostringstream str;
-       str.imbue(std::locale("C.UTF-8"));
+       str.imbue(std::locale::classic());
        str.precision(4);
        str << "dlstatus" << ':' << std::fixed << i << ':' << Percent << ':' << msg << '\n';
        auto const dlstatus = str.str();
diff --combined apt-pkg/deb/dpkgpm.cc
index 9c871d477616406220852a9531084249e80578d5,0ac74d4792a770c6ba624834d3393636a0fc77bc..9d1739d68032988ab67247d43e8b9607ab02d0e8
@@@ -61,6 -61,8 +61,8 @@@
  #include <apti18n.h>
                                                                        /*}}}*/
  
+ extern char **environ;
  using namespace std;
  
  APT_PURE static string AptHistoryRequestingUser()                     /*{{{*/
@@@ -1339,16 -1341,10 +1341,16 @@@ bool pkgDPkgPM::Go(APT::Progress::Packa
        std::distance(List.cbegin(), List.cend());
     ExpandPendingCalls(List, Cache);
  
 -   auto const StripAlreadyDoneFromPending = [&](APT::VersionVector & Pending) {
 +   /* if dpkg told us that it has already done everything to the package we wanted it to do,
 +      we shouldn't ask it for "more" later. That can e.g. happen if packages without conffiles
 +      are purged as they will have pass through the purge states on remove already */
 +   auto const StripAlreadyDoneFrom = [&](APT::VersionVector & Pending) {
        Pending.erase(std::remove_if(Pending.begin(), Pending.end(), [&](pkgCache::VerIterator const &Ver) {
            auto const PN = Ver.ParentPkg().FullName();
 -          return PackageOps[PN].size() <= PackageOpsDone[PN];
 +          auto const POD = PackageOpsDone.find(PN);
 +          if (POD == PackageOpsDone.end())
 +             return false;
 +          return PackageOps[PN].size() <= POD->second;
         }), Pending.end());
     };
  
            {
               if (I->File[0] != '/')
                  return _error->Error("Internal Error, Pathname to install is not absolute '%s'",I->File.c_str());
 -             auto const file = flNotDir(I->File);
 +             auto file = flNotDir(I->File);
 +             if (flExtension(file) != "deb")
 +                file.append(".deb");
               std::string linkpath;
               if (dpkg_recursive_install_numbered)
                  strprintf(linkpath, "%s/%.*lu-%s", tmpdir_to_free, p, n, file.c_str());
        else if (I->Op == Item::RemovePending)
        {
         ++I;
 -       StripAlreadyDoneFromPending(approvedStates.Remove());
 +       StripAlreadyDoneFrom(approvedStates.Remove());
         if (approvedStates.Remove().empty())
            continue;
        }
         ++I;
         // explicit removes of packages without conffiles passthrough the purge states instantly, too.
         // Setting these non-installed packages up for purging generates 'unknown pkg' warnings from dpkg
 -       StripAlreadyDoneFromPending(approvedStates.Purge());
 +       StripAlreadyDoneFrom(approvedStates.Purge());
         if (approvedStates.Purge().empty())
            continue;
         std::remove_reference<decltype(approvedStates.Remove())>::type approvedRemoves;
     if (d->dpkg_error.empty() == false)
     {
        // no point in reseting packages we already completed removal for
 -      StripAlreadyDoneFromPending(approvedStates.Remove());
 -      StripAlreadyDoneFromPending(approvedStates.Purge());
 +      StripAlreadyDoneFrom(approvedStates.Remove());
 +      StripAlreadyDoneFrom(approvedStates.Purge());
        APT::StateChanges undo;
        auto && undoRem = approvedStates.Remove();
        std::move(undoRem.begin(), undoRem.end(), std::back_inserter(undo.Install()));
        if (undo.Save(false) == false)
         _error->Error("Couldn't revert dpkg selection for approved remove/purge after an error was encountered!");
     }
 +
 +   StripAlreadyDoneFrom(currentStates.Remove());
 +   StripAlreadyDoneFrom(currentStates.Purge());
     if (currentStates.Save(false) == false)
        _error->Error("Couldn't restore dpkg selection states which were present before this interaction!");
  
diff --combined cmdline/apt-key.in
index 199903d61165af2fce677695d39108abe48ef49f,21df37ffdf4aa0f01ca3dc9424a4c4e5569bb17a..0c10e59554972fc62603306daa7c4370e822096f
@@@ -232,17 -232,6 +232,17 @@@ remove_key_from_keyring() 
      done
  }
  
 +accessible_file_exists() {
 +   if ! test -s "$1"; then
 +      return 1
 +   fi
 +   if test -r "$1"; then
 +      return 0
 +   fi
 +   warn "The key(s) in the keyring $1 are ignored as the file is not readable by user '$USER' executing apt-key."
 +   return 1
 +}
 +
  foreach_keyring_do() {
     local ACTION="$1"
     shift
        $ACTION "$FORCED_KEYRING" "$@"
     else
        # otherwise all known keyrings are up for inspection
 -      if [ -s "$TRUSTEDFILE" ]; then
 +      if accessible_file_exists "$TRUSTEDFILE"; then
            $ACTION "$TRUSTEDFILE" "$@"
        fi
        local TRUSTEDPARTS="/etc/apt/trusted.gpg.d"
            TRUSTEDPARTS="$(readlink -f "$TRUSTEDPARTS")"
            local TRUSTEDPARTSLIST="$(cd /; find "$TRUSTEDPARTS" -mindepth 1 -maxdepth 1 -name '*.gpg')"
            for trusted in $(echo "$TRUSTEDPARTSLIST" | sort); do
 -              if [ -s "$trusted" ]; then
 +              if accessible_file_exists "$trusted"; then
                    $ACTION "$trusted" "$@"
                fi
            done
@@@ -313,18 -302,35 +313,18 @@@ import_keyring_into_keyring() 
      fi
  }
  
 +catfile() {
 +   cat "$1" >> "$2"
 +}
 +
  merge_all_trusted_keyrings_into_pubring() {
      # does the same as:
      # foreach_keyring_do 'import_keys_from_keyring' "${GPGHOMEDIR}/pubring.gpg"
      # but without using gpg, just cat and find
-     local PUBRING="$(readlink -f "${GPGHOMEDIR}/pubring.gpg")"
+     local PUBRING="$(readlink -f "${GPGHOMEDIR}")/pubring.gpg"
 -    # if a --keyring was given, just use this one
 -    if [ -n "$FORCED_KEYRING" ]; then
 -      if [ -s "$FORCED_KEYRING" ]; then
 -          cp --dereference "$FORCED_KEYRING" "$PUBRING"
 -      fi
 -    else
 -      # otherwise all known keyrings are merged
 -      local TRUSTEDPARTS="/etc/apt/trusted.gpg.d"
 -      eval $(apt-config shell TRUSTEDPARTS Dir::Etc::TrustedParts/d)
 -      if [ -d "$TRUSTEDPARTS" ]; then
 -          rm -f "$PUBRING"
 -          if [ -s "$TRUSTEDFILE" ]; then
 -              cat "$TRUSTEDFILE" > "$PUBRING"
 -          fi
 -          TRUSTEDPARTS="$(readlink -f "$TRUSTEDPARTS")"
 -          (cd /; find "$TRUSTEDPARTS" -mindepth 1 -maxdepth 1 -name '*.gpg' -exec cat {} + >> "$PUBRING";)
 -      elif [ -s "$TRUSTEDFILE" ]; then
 -          cp --dereference "$TRUSTEDFILE" "$PUBRING"
 -      fi
 -    fi
 -
 -    if [ ! -s "$PUBRING" ]; then
 -      touch "$PUBRING"
 -    fi
 +    rm -f "$PUBRING"
 +    touch "$PUBRING"
 +    foreach_keyring_do 'catfile' "$PUBRING"
  }
  
  import_keys_from_keyring() {
@@@ -474,34 -480,8 +474,34 @@@ if [ -z "$command" ]; the
  fi
  shift
  
 +find_gpgv_status_fd() {
 +   while [ -n "$1" ]; do
 +      if [ "$1" = '--status-fd' ]; then
 +              shift
 +              echo "$1"
 +              break
 +      fi
 +      shift
 +   done
 +}
 +GPGSTATUSFD="$(find_gpgv_status_fd "$@")"
 +
 +warn() {
 +    if [ -z "$GPGHOMEDIR" ]; then
 +      echo >&2 'W:' "$@"
 +    else
 +      echo 'W:' "$@" > "${GPGHOMEDIR}/aptwarnings.log"
 +    fi
 +    if [ -n "$GPGSTATUSFD" ]; then
 +      echo >&${GPGSTATUSFD} '[APTKEY:] WARNING' "$@"
 +    fi
 +}
 +
  cleanup_gpg_home() {
      if [ -z "$GPGHOMEDIR" ]; then return; fi
 +    if [ -s "$GPGHOMEDIR/aptwarnings.log" ]; then
 +      cat >&2 "$GPGHOMEDIR/aptwarnings.log"
 +    fi
      if command_available 'gpgconf'; then
        GNUPGHOME="${GPGHOMEDIR}" gpgconf --kill gpg-agent >/dev/null 2>&1 || true
      fi
index 0daf776f58ba24ae197ee7def285dd8beb99c1d0,c513ed12cceed851bfca78f9644c35d77271c315..62720fedd8f8d70fa05fe4a495f3026bd75ef7a1
@@@ -31,7 -31,6 +31,6 @@@ if [ "${MSGCOLOR:-YES}" = 'YES' ]; the
        fi
  fi
  
  if [ "$MSGCOLOR" != 'NO' ]; then
        CERROR="\033[1;31m" # red
        CWARNING="\033[1;33m" # yellow
@@@ -196,6 -195,9 +195,9 @@@ aptinternalplanner() { runapt "${APTINT
  dpkg() {
        "${TMPWORKINGDIRECTORY}/rootdir/usr/bin/dpkg" "$@"
  }
+ dpkg_version() {
+       command perl -MDpkg -E 'say $Dpkg::PROGVERSION'
+ }
  dpkgcheckbuilddeps() {
        command dpkg-checkbuilddeps --admindir="${TMPWORKINGDIRECTORY}/rootdir/var/lib/dpkg" "$@"
  }
@@@ -276,8 -278,13 +278,13 @@@ find_project_binary_dir() 
        fi
  }
  setupenvironment() {
+       # Next check needs a gnu stat, let's figure that out early.
+       stat=stat
+       if command -v gnustat >/dev/null 2>&1; then
+               stat=gnustat
+       fi
        # privilege dropping and testing doesn't work if /tmp isn't world-writeable (as e.g. with libpam-tmpdir)
-       if [ -n "$TMPDIR" ] && [ "$(id -u)" = '0' ] && [ "$(stat --format '%a' "$TMPDIR")" != '1777' ]; then
+       if [ -n "$TMPDIR" ] && [ "$(id -u)" = '0' ] && [ "$($stat --format '%a' "$TMPDIR")" != '1777' ]; then
                unset TMPDIR
        fi
        TMPWORKINGDIRECTORY="$(mktemp -d)"
        fi
        msgninfo "Preparing environment for ${0##*/} in ${TMPWORKINGDIRECTORY}…"
  
+       # Setup coreutils on BSD systems
+       mkdir "${TMPWORKINGDIRECTORY}/bin"
+       for prefix in gnu g; do
+                       for command in stat touch sed cp tr sha1sum sha256sum md5sum sha512sum grep date wc chmod head readlink tar expr base64; do
+                                       if command -v $prefix$command 2>/dev/null >/dev/null; then
+                                                       [ -e "${TMPWORKINGDIRECTORY}/bin/$command" ] || ln -sf $(command -v $prefix$command)  "${TMPWORKINGDIRECTORY}/bin/$command"
+                                       fi
+                       done
+       done
+       export PATH="${TMPWORKINGDIRECTORY}/bin/:$PATH"
        mkdir -m 700 "${TMPWORKINGDIRECTORY}/downloaded"
        if [ "$(id -u)" = '0' ]; then
                # relax permissions so that running as root with user switching works
                umask 022
                chmod 711 "$TMPWORKINGDIRECTORY"
-               chown _apt:root "${TMPWORKINGDIRECTORY}/downloaded"
+               chown _apt:$(id -gn) "${TMPWORKINGDIRECTORY}/downloaded"
        fi
  
        TESTDIRECTORY="$(readlink -f "$(dirname $0)")"
        ln -s "${TMPWORKINGDIRECTORY}/keys/joesixpack.pub" rootdir/etc/apt/trusted.gpg.d/joesixpack.gpg
  
        echo "Dir \"${TMPWORKINGDIRECTORY}/rootdir\";" >> aptconfig.conf
+       echo "Dir::Etc \"etc\";" >> aptconfig.conf
+       echo "Dir::State \"var/lib/apt\";" >> aptconfig.conf
+       echo "Dir::Cache \"var/cache/apt\";" >> aptconfig.conf
+       echo "Dir::Etc \"etc/apt\";" >> aptconfig.conf
+       echo "Dir::Log \"var/log/apt\";" >> aptconfig.conf
        echo "APT::Get::Show-User-Simulation-Note \"false\";" >> aptconfig.conf
        echo "Dir::Bin::Methods \"${TMPWORKINGDIRECTORY}/rootdir/usr/lib/apt/methods\";" >> aptconfig.conf
        # either store apt-key were we can access it, even if we run it as a different user
@@@ -386,11 -410,13 +410,13 @@@ EO
        cp "${TMPWORKINGDIRECTORY}/rootdir/usr/bin/dpkg" "${TMPWORKINGDIRECTORY}/rootdir/usr/bin/gdb-dpkg"
        cat >> "${TMPWORKINGDIRECTORY}/rootdir/usr/bin/dpkg" <<EOF
  exec fakeroot '${DPKG:-dpkg}' --root='${TMPWORKINGDIRECTORY}/rootdir' \\
+       --admindir="${TMPWORKINGDIRECTORY}/rootdir/var/lib/dpkg" \\
        --log='${TMPWORKINGDIRECTORY}/rootdir/var/log/dpkg.log' \\
        --force-not-root --force-bad-path "\$@"
  EOF
        cat >> "${TMPWORKINGDIRECTORY}/rootdir/usr/bin/gdb-dpkg" <<EOF
  exec fakeroot gdb --quiet -ex run '${DPKG:-dpkg}' --args '${DPKG:-dpkg}' --root='${TMPWORKINGDIRECTORY}/rootdir' \\
+       --admindir="${TMPWORKINGDIRECTORY}/rootdir/var/lib/dpkg" \\
        --log='${TMPWORKINGDIRECTORY}/rootdir/var/log/dpkg.log' \\
        --force-not-root --force-bad-path "\$@"
  EOF
  
        cp "${TESTDIRECTORY}/apt.pem" "${TMPWORKINGDIRECTORY}/rootdir/etc/webserver.pem"
        if [ "$(id -u)" = '0' ]; then
-               chown _apt:root "${TMPWORKINGDIRECTORY}/rootdir/etc/webserver.pem"
+               chown _apt:$(id -gn) "${TMPWORKINGDIRECTORY}/rootdir/etc/webserver.pem"
        fi
        echo "Acquire::https::CaInfo \"${TMPWORKINGDIRECTORY}/rootdir/etc/webserver.pem\";" > rootdir/etc/apt/apt.conf.d/99https
        echo "Apt::Cmd::Disable-Script-Warning \"1\";" > rootdir/etc/apt/apt.conf.d/apt-binary
  
        # create some files in /tmp and look at user/group to get what this means
        TEST_DEFAULT_USER="$(id -un)"
-       if [ "$(uname)" = 'GNU/kFreeBSD' ]; then
-               TEST_DEFAULT_GROUP='root'
-       else
-               TEST_DEFAULT_GROUP="$(id -gn)"
-       fi
+       touch "${TMPWORKINGDIRECTORY}/test-file"
+       TEST_DEFAULT_GROUP=$(stat --format '%G'  "${TMPWORKINGDIRECTORY}/test-file")
  
        # cleanup the environment a bit
        # prefer our apt binaries over the system apt binaries
        export PATH="${BUILDDIRECTORY}:${PATH}:/usr/local/sbin:/usr/sbin:/sbin"
-       export LC_ALL=C.UTF-8
+       export LC_ALL=C
        unset LANGUAGE APT_CONFIG
        unset GREP_OPTIONS DEB_BUILD_PROFILES
        unset http_proxy HTTP_PROXY https_proxy HTTPS_PROXY no_proxy
@@@ -500,7 -523,15 +523,15 @@@ configdpkg() 
                fi
        fi
        rm -f rootdir/etc/apt/apt.conf.d/00foreigndpkg
-       if command dpkg --assert-multi-arch >/dev/null 2>&1 ; then
+       # if multi-arch make sure dpkg can detect itself as capable of it
+       if getarchitectures | grep -E -q '[^ ]+ [^ ]+'; then
+               if [ "0" = "$(dpkg -l dpkg 2> /dev/null | grep '^i' | wc -l)" ]; then
+                       # dpkg doesn't really check the version as long as it is fully installed,
+                       # but just to be sure we choose one above the required version
+                       insertinstalledpackage 'dpkg' "all" '1.16.2+fake'
+               fi
+       fi
+       if dpkg --assert-multi-arch >/dev/null 2>&1 ; then
                local ARCHS="$(getarchitectures)"
                local DPKGARCH="$(dpkg --print-architecture)"
                # this ensures that even if multi-arch isn't active in the view
                                fi
                        fi
                done
-               # if multi-arch make sure dpkg can detect itself as capable of it
-               if echo "$ARCHS" | grep -E -q '[^ ]+ [^ ]+'; then
-                       if [ "0" = "$(dpkg -l dpkg 2> /dev/null | grep '^i' | wc -l)" ]; then
-                               # dpkg doesn't really check the version as long as it is fully installed,
-                               # but just to be sure we choose one above the required version
-                               insertinstalledpackage 'dpkg' "all" '1.16.2+fake'
-                       fi
-               fi
        fi
  }
  
@@@ -568,7 -591,11 +591,11 @@@ int execvp(const char *file, char *cons
        return func_execvp(newfile, argv);
  }
  EOF
-       testempty --nomsg gcc -Wall -Wextra -fPIC -shared -o noopchroot.so noopchroot.c -ldl
+       if cc -ldl 2>&1 | grep -q dl; then
+               testempty --nomsg cc -Wall -Wextra -fPIC -shared -o noopchroot.so noopchroot.c
+       else
+               testempty --nomsg cc -Wall -Wextra -fPIC -shared -o noopchroot.so noopchroot.c -ldl
+       fi
  }
  configcompression() {
        if [ "$1" = 'ALL' ]; then
@@@ -626,10 -653,10 +653,10 @@@ _setupsimplenativepackage() 
        local VERSION="$3"
        local RELEASE="${4:-unstable}"
        local DEPENDENCIES="$5"
-       local DESCRIPTION="${6:-"an autogenerated dummy ${NAME}=${VERSION}/${RELEASE}
+       local DESCRIPTION="${6:-an autogenerated dummy ${NAME}=${VERSION}/${RELEASE}
   If you find such a package installed on your system,
   something went horribly wrong! They are autogenerated
-  und used only by testcases and serve no other purpose…"}"
+  und used only by testcases and serve no other purpose…}"
  
        local SECTION="${7:-others}"
        local PRIORITY="${8:-optional}"
@@@ -662,7 -689,7 +689,7 @@@ Standards-Version: 3.9.3
                if [ "$SECTION" != '<none>' ]; then
                        echo "Section: $SECTION"
                fi
-               local BUILDDEPS="$(echo "$DEPENDENCIES" | grep '^Build-')"
+               local BUILDDEPS="$(printf "%b\n" "$DEPENDENCIES" | grep '^Build-')"
                test -z "$BUILDDEPS" || echo "$BUILDDEPS"
                echo "
  Package: $NAME"
                else
                        echo "Architecture: any"
                fi
-               local DEPS="$(echo "$DEPENDENCIES" | grep -v '^Build-')"
+               local DEPS="$(printf "%b\n" "$DEPENDENCIES" | grep -v '^Build-')"
                test -z "$DEPS" || echo "$DEPS"
-               echo "Description: $DESCRIPTION"
+               printf "%b\n" "Description: $DESCRIPTION"
        } > "${BUILDDIR}/debian/control"
  
        echo '3.0 (native)' > "${BUILDDIR}/debian/source/format"
  }
  
+ make_tiny_rules() {
+       local OUT="$1"
+       if command -v gmake >/dev/null 2>&1; then
+               [ -e ${TMPWORKINGDIRECTORY}/bin/make ] || ln -s $(command -v gmake) ${TMPWORKINGDIRECTORY}/bin/make
+               echo "#!${TMPWORKINGDIRECTORY}/bin/make -f" > "$OUT"
+       else
+               echo '#!/usr/bin/make -f' > "$OUT"
+       fi
+       echo '%:' >> "$OUT"
+       echo '  dh $@' >> "$OUT"
+ }
  setupsimplenativepackage() {
        _setupsimplenativepackage "$@"
        local NAME="$1"
        local VERSION="$3"
        local BUILDDIR="${TMPWORKINGDIRECTORY}/incoming/${NAME}-${VERSION}"
        test -e "${BUILDDIR}/debian/compat" || echo '7' > "${BUILDDIR}/debian/compat"
-       test -e  "${BUILDDIR}/debian/rules" || cp /usr/share/doc/debhelper/examples/rules.tiny "${BUILDDIR}/debian/rules"
+       test -e  "${BUILDDIR}/debian/rules" || make_tiny_rules "${BUILDDIR}/debian/rules"
  }
  
  buildsimplenativepackage() {
@@@ -844,10 -883,10 +883,10 @@@ insertpackage() 
        local VERSION="$4"
        local DEPENDENCIES="$5"
        local PRIORITY="${6:-optional}"
-       local DESCRIPTION="${7:-"an autogenerated dummy ${NAME}=${VERSION}/${RELEASES}
+       local DESCRIPTION="${7:-an autogenerated dummy ${NAME}=${VERSION}/${RELEASES}
   If you find such a package installed on your system,
   something went horribly wrong! They are autogenerated
-  und used only by testcases and serve no other purpose…"}"
+  und used only by testcases and serve no other purpose…}"
        local ARCHS=""
        for RELEASE in $(printf '%s' "$RELEASES" | tr ',' '\n'); do
                if [ "$RELEASE" = 'installed' ]; then
@@@ -872,10 -911,9 +911,10 @@@ Maintainer: Joe Sixpack <joe@example.or
                                        test "$arch" = 'none' || echo "Architecture: $arch"
                                        echo "Version: $VERSION
  Filename: pool/main/${NAME}/${NAME}_${VERSION}_${arch}.deb"
-                                       test -z "$DEPENDENCIES" || echo "$DEPENDENCIES"
+                                       test -z "$DEPENDENCIES" || printf "%b\n" "$DEPENDENCIES"
                                        echo "Description: $(printf '%s' "$DESCRIPTION" | head -n 1)"
                                        echo "Description-md5: $(printf '%s' "$DESCRIPTION" | md5sum | cut -d' ' -f 1)"
 +                                      echo "SHA256: 0000000000000000000000000000000000000000000000000000000000000000"
                                        echo
                                } >> "${PPATH}/Packages"
                        done
@@@ -908,7 -946,7 +947,7 @@@ Binary: $BINAR
  Version: $VERSION
  Maintainer: Joe Sixpack <joe@example.org>
  Architecture: $ARCH" >> $FILE
-               test -z "$DEPENDENCIES" || echo "$DEPENDENCIES" >> "$FILE"
+               test -z "$DEPENDENCIES" || printf "%b\n" "$DEPENDENCIES" >> "$FILE"
                echo "Files:
   $(echo -n "$DSCFILE" | md5sum | cut -d' ' -f 1) $(echo -n "$DSCFILE" | wc -c) "$DSCFILE"
   $(echo -n "$TARFILE" | md5sum | cut -d' ' -f 1) $(echo -n "$TARFILE" | wc -c) "$TARFILE"
@@@ -926,10 -964,10 +965,10 @@@ insertinstalledpackage() 
        local DEPENDENCIES="$4"
        local PRIORITY="${5:-optional}"
        local STATUS="${6:-install ok installed}"
-       local DESCRIPTION="${7:-"an autogenerated dummy ${NAME}=${VERSION}/installed
+       local DESCRIPTION="${7:-an autogenerated dummy ${NAME}=${VERSION}/installed
   If you find such a package installed on your system,
   something went horribly wrong! They are autogenerated
-  und used only by testcases and serve no other purpose…"}"
+  und used only by testcases and serve no other purpose…}"
  
        local FILE='rootdir/var/lib/dpkg/status'
        local INFO='rootdir/var/lib/dpkg/info'
@@@ -942,8 -980,8 +981,8 @@@ Installed-Size: 4
  Maintainer: Joe Sixpack <joe@example.org>
  Version: $VERSION" >> "$FILE"
                test "$arch" = 'none' || echo "Architecture: $arch" >> "$FILE"
-               test -z "$DEPENDENCIES" || echo "$DEPENDENCIES" >> "$FILE"
-               echo "Description: $DESCRIPTION" >> "$FILE"
+               test -z "$DEPENDENCIES" || printf "%b\n" "$DEPENDENCIES" >> "$FILE"
+               printf "%b\n" "Description: $DESCRIPTION" >> "$FILE"
                echo >> "$FILE"
                if [ "$(dpkg-query -W --showformat='${Multi-Arch}')" = 'same' ]; then
                        echo -n > "${INFO}/${NAME}:${arch}.list"
@@@ -1276,7 -1314,12 +1315,12 @@@ changetowebserver() 
  }
  
  changetohttpswebserver() {
-       if ! command -v stunnel4 >/dev/null 2>&1; then
+       local stunnel4
+       if command -v stunnel4 >/dev/null 2>&1; then
+               stunnel4=stunnel4
+       elif command -v stunnel >/dev/null 2>&1; then
+               stunnel4=stunnel
+       else
                msgdie 'You need to install stunnel4 for https testcases'
        fi
        if [ ! -e "${TMPWORKINGDIRECTORY}/aptarchive/aptwebserver.pid" ]; then
@@@ -1290,14 -1333,14 +1334,14 @@@ output = /dev/nul
  accept = 0
  connect = $APTHTTPPORT
  " > "${TMPWORKINGDIRECTORY}/stunnel.conf"
-       stunnel4 "${TMPWORKINGDIRECTORY}/stunnel.conf"
+       $stunnel4 "${TMPWORKINGDIRECTORY}/stunnel.conf"
          waitforpidfile "${TMPWORKINGDIRECTORY}/aptarchive/stunnel.pid"
        local PID="$(cat "${TMPWORKINGDIRECTORY}/aptarchive/stunnel.pid")"
          if [ -z "$PID" ]; then
-               msgdie 'Could not fork stunnel4 successfully'
+               msgdie 'Could not fork $stunnel4 successfully'
        fi
        addtrap 'prefix' "kill ${PID};"
-       APTHTTPSPORT="$(lsof -i -n | awk "/^stunnel4 / && \$2 == \"${PID}\" {print \$9; exit; }" | cut -d':' -f 2)"
+       APTHTTPSPORT="$(lsof -i -n | awk "/^$stunnel4 / && \$2 == \"${PID}\" {print \$9; exit; }" | cut -d':' -f 2)"
        webserverconfig 'aptwebserver::port::https' "$APTHTTPSPORT" "https://localhost:${APTHTTPSPORT}"
        rewritesourceslist "https://localhost:${APTHTTPSPORT}/"
  }
@@@ -1917,7 -1960,7 +1961,7 @@@ mkdir() 
                command mkdir -m 700 -p "${TMPWORKINGDIRECTORY}/rootdir/var/lib/apt/lists/partial"
                touch "${TMPWORKINGDIRECTORY}/rootdir/var/lib/apt/lists/lock"
                if [ "$(id -u)" = '0' ]; then
-                       chown _apt:root "${TMPWORKINGDIRECTORY}/rootdir/var/lib/apt/lists/partial"
+                       chown _apt:$(id -gn) "${TMPWORKINGDIRECTORY}/rootdir/var/lib/apt/lists/partial"
                fi
        else
                command mkdir "$@"
@@@ -1989,7 -2032,7 +2033,7 @@@ testaptautotestnodpkgwarning() 
                if expr match "$2" '^-dy\?' >/dev/null 2>&1; then return; fi # download-only mode
                shift
        done
 -      testfailure grep '^dpkg: warning:.*ignor.*' "${TMPWORKINGDIRECTORY}/rootdir/tmp-before/${TESTCALL}.output"
 +      testfailure grep '^dpkg: warning:.*\(ignor\|unknown\).*' "${TMPWORKINGDIRECTORY}/rootdir/tmp-before/${TESTCALL}.output"
  }
  
  aptautotest_aptget_install() { testaptautotestnodpkgwarning "$@"; }