| 1 | // Include Files /*{{{*/ |
| 2 | #include <config.h> |
| 3 | |
| 4 | #include <apt-pkg/acquire.h> |
| 5 | #include <apt-pkg/acquire-item.h> |
| 6 | #include <apt-pkg/cacheset.h> |
| 7 | #include <apt-pkg/cmndline.h> |
| 8 | #include <apt-pkg/clean.h> |
| 9 | #include <apt-pkg/configuration.h> |
| 10 | #include <apt-pkg/error.h> |
| 11 | #include <apt-pkg/fileutl.h> |
| 12 | #include <apt-pkg/strutl.h> |
| 13 | |
| 14 | #include <apt-private/private-cachefile.h> |
| 15 | #include <apt-private/private-download.h> |
| 16 | #include <apt-private/private-output.h> |
| 17 | #include <apt-private/private-utils.h> |
| 18 | #include <apt-private/acqprogress.h> |
| 19 | |
| 20 | #include <fstream> |
| 21 | #include <string> |
| 22 | #include <vector> |
| 23 | |
| 24 | #include <unistd.h> |
| 25 | #include <sys/types.h> |
| 26 | #include <pwd.h> |
| 27 | #include <fcntl.h> |
| 28 | #include <sys/vfs.h> |
| 29 | #include <sys/statvfs.h> |
| 30 | #include <sys/stat.h> |
| 31 | #include <errno.h> |
| 32 | |
| 33 | #include <apti18n.h> |
| 34 | /*}}}*/ |
| 35 | |
| 36 | // CheckAuth - check if each download comes form a trusted source /*{{{*/ |
| 37 | bool CheckAuth(pkgAcquire& Fetcher, bool const PromptUser) |
| 38 | { |
| 39 | std::vector<std::string> UntrustedList; |
| 40 | for (pkgAcquire::ItemIterator I = Fetcher.ItemsBegin(); I < Fetcher.ItemsEnd(); ++I) |
| 41 | if (!(*I)->IsTrusted()) |
| 42 | UntrustedList.push_back((*I)->ShortDesc()); |
| 43 | |
| 44 | if (UntrustedList.empty()) |
| 45 | return true; |
| 46 | |
| 47 | return AuthPrompt(UntrustedList, PromptUser); |
| 48 | } |
| 49 | /*}}}*/ |
| 50 | bool AuthPrompt(std::vector<std::string> const &UntrustedList, bool const PromptUser)/*{{{*/ |
| 51 | { |
| 52 | ShowList(c2out,_("WARNING: The following packages cannot be authenticated!"), UntrustedList, |
| 53 | [](std::string const&) { return true; }, |
| 54 | [](std::string const&str) { return str; }, |
| 55 | [](std::string const&) { return ""; }); |
| 56 | |
| 57 | if (_config->FindB("APT::Get::AllowUnauthenticated",false) == true) |
| 58 | { |
| 59 | c2out << _("Authentication warning overridden.\n"); |
| 60 | return true; |
| 61 | } |
| 62 | |
| 63 | if (PromptUser == false) |
| 64 | return _error->Error(_("Some packages could not be authenticated")); |
| 65 | |
| 66 | if (_config->FindI("quiet",0) < 2 |
| 67 | && _config->FindB("APT::Get::Assume-Yes",false) == false) |
| 68 | { |
| 69 | c2out << _("Install these packages without verification?") << std::flush; |
| 70 | if (!YnPrompt(false)) |
| 71 | return _error->Error(_("Some packages could not be authenticated")); |
| 72 | |
| 73 | return true; |
| 74 | } |
| 75 | else if (_config->FindB("APT::Get::Force-Yes",false) == true) { |
| 76 | _error->Warning(_("--force-yes is deprecated, use one of the options starting with --allow instead.")); |
| 77 | return true; |
| 78 | } |
| 79 | |
| 80 | return _error->Error(_("There were unauthenticated packages and -y was used without --allow-unauthenticated")); |
| 81 | } |
| 82 | /*}}}*/ |
| 83 | bool AcquireRun(pkgAcquire &Fetcher, int const PulseInterval, bool * const Failure, bool * const TransientNetworkFailure)/*{{{*/ |
| 84 | { |
| 85 | pkgAcquire::RunResult res; |
| 86 | if(PulseInterval > 0) |
| 87 | res = Fetcher.Run(PulseInterval); |
| 88 | else |
| 89 | res = Fetcher.Run(); |
| 90 | |
| 91 | if (res == pkgAcquire::Failed) |
| 92 | return false; |
| 93 | |
| 94 | for (pkgAcquire::ItemIterator I = Fetcher.ItemsBegin(); |
| 95 | I != Fetcher.ItemsEnd(); ++I) |
| 96 | { |
| 97 | |
| 98 | if ((*I)->Status == pkgAcquire::Item::StatDone && |
| 99 | (*I)->Complete == true) |
| 100 | continue; |
| 101 | |
| 102 | if (TransientNetworkFailure != NULL && (*I)->Status == pkgAcquire::Item::StatIdle) |
| 103 | { |
| 104 | *TransientNetworkFailure = true; |
| 105 | continue; |
| 106 | } |
| 107 | |
| 108 | ::URI uri((*I)->DescURI()); |
| 109 | uri.User.clear(); |
| 110 | uri.Password.clear(); |
| 111 | std::string descUri = std::string(uri); |
| 112 | _error->Error(_("Failed to fetch %s %s\n"), descUri.c_str(), |
| 113 | (*I)->ErrorText.c_str()); |
| 114 | |
| 115 | if (Failure != NULL) |
| 116 | *Failure = true; |
| 117 | } |
| 118 | |
| 119 | return true; |
| 120 | } |
| 121 | /*}}}*/ |
| 122 | bool CheckFreeSpaceBeforeDownload(std::string const &Dir, unsigned long long FetchBytes)/*{{{*/ |
| 123 | { |
| 124 | uint32_t const RAMFS_MAGIC = 0x858458f6; |
| 125 | /* Check for enough free space, but only if we are actually going to |
| 126 | download */ |
| 127 | if (_config->FindB("APT::Get::Print-URIs", false) == true || |
| 128 | _config->FindB("APT::Get::Download", true) == false) |
| 129 | return true; |
| 130 | |
| 131 | struct statvfs Buf; |
| 132 | if (statvfs(Dir.c_str(),&Buf) != 0) { |
| 133 | if (errno == EOVERFLOW) |
| 134 | return _error->WarningE("statvfs",_("Couldn't determine free space in %s"), |
| 135 | Dir.c_str()); |
| 136 | else |
| 137 | return _error->Errno("statvfs",_("Couldn't determine free space in %s"), |
| 138 | Dir.c_str()); |
| 139 | } |
| 140 | else |
| 141 | { |
| 142 | unsigned long long const FreeBlocks = _config->Find("APT::Sandbox::User").empty() ? Buf.f_bfree : Buf.f_bavail; |
| 143 | if (FreeBlocks < (FetchBytes / Buf.f_bsize)) |
| 144 | { |
| 145 | struct statfs Stat; |
| 146 | if (statfs(Dir.c_str(),&Stat) != 0 |
| 147 | #if HAVE_STRUCT_STATFS_F_TYPE |
| 148 | || Stat.f_type != RAMFS_MAGIC |
| 149 | #endif |
| 150 | ) |
| 151 | return _error->Error(_("You don't have enough free space in %s."), |
| 152 | Dir.c_str()); |
| 153 | } |
| 154 | } |
| 155 | return true; |
| 156 | } |
| 157 | /*}}}*/ |
| 158 | |
| 159 | aptAcquireWithTextStatus::aptAcquireWithTextStatus() : pkgAcquire::pkgAcquire(), |
| 160 | Stat(std::cout, ScreenWidth, _config->FindI("quiet",0)) |
| 161 | { |
| 162 | SetLog(&Stat); |
| 163 | } |
| 164 | |
| 165 | // DoDownload - download a binary /*{{{*/ |
| 166 | bool DoDownload(CommandLine &CmdL) |
| 167 | { |
| 168 | CacheFile Cache; |
| 169 | if (Cache.ReadOnlyOpen() == false) |
| 170 | return false; |
| 171 | |
| 172 | APT::CacheSetHelper helper; |
| 173 | APT::VersionSet verset = APT::VersionSet::FromCommandLine(Cache, |
| 174 | CmdL.FileList + 1, APT::CacheSetHelper::CANDIDATE, helper); |
| 175 | |
| 176 | if (verset.empty() == true) |
| 177 | return false; |
| 178 | |
| 179 | pkgRecords Recs(Cache); |
| 180 | pkgSourceList *SrcList = Cache.GetSourceList(); |
| 181 | |
| 182 | // reuse the usual acquire methods for deb files, but don't drop them into |
| 183 | // the usual directories - keep everything in the current directory |
| 184 | aptAcquireWithTextStatus Fetcher; |
| 185 | std::vector<std::string> storefile(verset.size()); |
| 186 | std::string const cwd = SafeGetCWD(); |
| 187 | _config->Set("Dir::Cache::Archives", cwd); |
| 188 | int i = 0; |
| 189 | for (APT::VersionSet::const_iterator Ver = verset.begin(); |
| 190 | Ver != verset.end(); ++Ver, ++i) |
| 191 | { |
| 192 | pkgAcquire::Item *I = new pkgAcqArchive(&Fetcher, SrcList, &Recs, *Ver, storefile[i]); |
| 193 | if (storefile[i].empty()) |
| 194 | continue; |
| 195 | std::string const filename = cwd + flNotDir(storefile[i]); |
| 196 | storefile[i].assign(filename); |
| 197 | I->DestFile.assign(filename); |
| 198 | } |
| 199 | |
| 200 | // Just print out the uris and exit if the --print-uris flag was used |
| 201 | if (_config->FindB("APT::Get::Print-URIs") == true) |
| 202 | { |
| 203 | pkgAcquire::UriIterator I = Fetcher.UriBegin(); |
| 204 | for (; I != Fetcher.UriEnd(); ++I) |
| 205 | std::cout << '\'' << I->URI << "' " << flNotDir(I->Owner->DestFile) << ' ' << |
| 206 | I->Owner->FileSize << ' ' << I->Owner->HashSum() << std::endl; |
| 207 | return true; |
| 208 | } |
| 209 | |
| 210 | if (_error->PendingError() == true || CheckAuth(Fetcher, false) == false) |
| 211 | return false; |
| 212 | |
| 213 | bool Failed = false; |
| 214 | if (AcquireRun(Fetcher, 0, &Failed, NULL) == false) |
| 215 | return false; |
| 216 | |
| 217 | // copy files in local sources to the current directory |
| 218 | for (pkgAcquire::ItemIterator I = Fetcher.ItemsBegin(); I != Fetcher.ItemsEnd(); ++I) |
| 219 | { |
| 220 | std::string const filename = cwd + flNotDir((*I)->DestFile); |
| 221 | if ((*I)->Local == true && |
| 222 | filename != (*I)->DestFile && |
| 223 | (*I)->Status == pkgAcquire::Item::StatDone) |
| 224 | { |
| 225 | std::ifstream src((*I)->DestFile.c_str(), std::ios::binary); |
| 226 | std::ofstream dst(filename.c_str(), std::ios::binary); |
| 227 | dst << src.rdbuf(); |
| 228 | chmod(filename.c_str(), 0644); |
| 229 | } |
| 230 | } |
| 231 | return Failed == false; |
| 232 | } |
| 233 | /*}}}*/ |
| 234 | // DoChangelog - Get changelog from the command line /*{{{*/ |
| 235 | bool DoChangelog(CommandLine &CmdL) |
| 236 | { |
| 237 | CacheFile Cache; |
| 238 | if (Cache.ReadOnlyOpen() == false) |
| 239 | return false; |
| 240 | |
| 241 | APT::CacheSetHelper helper; |
| 242 | APT::VersionList verset = APT::VersionList::FromCommandLine(Cache, |
| 243 | CmdL.FileList + 1, APT::CacheSetHelper::CANDIDATE, helper); |
| 244 | if (verset.empty() == true) |
| 245 | return false; |
| 246 | |
| 247 | bool const downOnly = _config->FindB("APT::Get::Download-Only", false); |
| 248 | bool const printOnly = _config->FindB("APT::Get::Print-URIs", false); |
| 249 | |
| 250 | aptAcquireWithTextStatus Fetcher; |
| 251 | for (APT::VersionList::const_iterator Ver = verset.begin(); |
| 252 | Ver != verset.end(); |
| 253 | ++Ver) |
| 254 | { |
| 255 | if (printOnly) |
| 256 | new pkgAcqChangelog(&Fetcher, Ver, "/dev/null"); |
| 257 | else if (downOnly) |
| 258 | new pkgAcqChangelog(&Fetcher, Ver, "."); |
| 259 | else |
| 260 | new pkgAcqChangelog(&Fetcher, Ver); |
| 261 | } |
| 262 | |
| 263 | if (printOnly == false) |
| 264 | { |
| 265 | bool Failed = false; |
| 266 | if (AcquireRun(Fetcher, 0, &Failed, NULL) == false || Failed == true) |
| 267 | return false; |
| 268 | } |
| 269 | |
| 270 | if (downOnly == false || printOnly == true) |
| 271 | { |
| 272 | bool Failed = false; |
| 273 | for (pkgAcquire::ItemIterator I = Fetcher.ItemsBegin(); I != Fetcher.ItemsEnd(); ++I) |
| 274 | { |
| 275 | if (printOnly) |
| 276 | { |
| 277 | if ((*I)->ErrorText.empty() == false) |
| 278 | { |
| 279 | Failed = true; |
| 280 | _error->Error("%s", (*I)->ErrorText.c_str()); |
| 281 | } |
| 282 | else |
| 283 | std::cout << '\'' << (*I)->DescURI() << "' " << flNotDir((*I)->DestFile) << std::endl; |
| 284 | } |
| 285 | else |
| 286 | DisplayFileInPager((*I)->DestFile); |
| 287 | } |
| 288 | return Failed == false; |
| 289 | } |
| 290 | |
| 291 | return true; |
| 292 | } |
| 293 | /*}}}*/ |
| 294 | |
| 295 | // DoClean - Remove download archives /*{{{*/ |
| 296 | bool DoClean(CommandLine &) |
| 297 | { |
| 298 | std::string const archivedir = _config->FindDir("Dir::Cache::archives"); |
| 299 | std::string const listsdir = _config->FindDir("Dir::state::lists"); |
| 300 | |
| 301 | if (_config->FindB("APT::Get::Simulate") == true) |
| 302 | { |
| 303 | std::string const pkgcache = _config->FindFile("Dir::cache::pkgcache"); |
| 304 | std::string const srcpkgcache = _config->FindFile("Dir::cache::srcpkgcache"); |
| 305 | std::cout << "Del " << archivedir << "* " << archivedir << "partial/*"<< std::endl |
| 306 | << "Del " << listsdir << "partial/*" << std::endl |
| 307 | << "Del " << pkgcache << " " << srcpkgcache << std::endl; |
| 308 | return true; |
| 309 | } |
| 310 | |
| 311 | pkgAcquire Fetcher; |
| 312 | if (archivedir.empty() == false && FileExists(archivedir) == true && |
| 313 | Fetcher.GetLock(archivedir) == true) |
| 314 | { |
| 315 | Fetcher.Clean(archivedir); |
| 316 | Fetcher.Clean(archivedir + "partial/"); |
| 317 | } |
| 318 | |
| 319 | if (listsdir.empty() == false && FileExists(listsdir) == true && |
| 320 | Fetcher.GetLock(listsdir) == true) |
| 321 | { |
| 322 | Fetcher.Clean(listsdir + "partial/"); |
| 323 | } |
| 324 | |
| 325 | pkgCacheFile::RemoveCaches(); |
| 326 | |
| 327 | return true; |
| 328 | } |
| 329 | /*}}}*/ |
| 330 | // DoAutoClean - Smartly remove downloaded archives /*{{{*/ |
| 331 | // --------------------------------------------------------------------- |
| 332 | /* This is similar to clean but it only purges things that cannot be |
| 333 | downloaded, that is old versions of cached packages. */ |
| 334 | class LogCleaner : public pkgArchiveCleaner |
| 335 | { |
| 336 | protected: |
| 337 | virtual void Erase(const char *File, std::string Pkg, std::string Ver,struct stat &St) APT_OVERRIDE |
| 338 | { |
| 339 | c1out << "Del " << Pkg << " " << Ver << " [" << SizeToStr(St.st_size) << "B]" << std::endl; |
| 340 | |
| 341 | if (_config->FindB("APT::Get::Simulate") == false) |
| 342 | RemoveFile("Cleaner::Erase", File); |
| 343 | }; |
| 344 | }; |
| 345 | bool DoAutoClean(CommandLine &) |
| 346 | { |
| 347 | std::string const archivedir = _config->FindDir("Dir::Cache::Archives"); |
| 348 | if (FileExists(archivedir) == false) |
| 349 | return true; |
| 350 | |
| 351 | // Lock the archive directory |
| 352 | FileFd Lock; |
| 353 | if (_config->FindB("Debug::NoLocking",false) == false) |
| 354 | { |
| 355 | int lock_fd = GetLock(flCombine(archivedir, "lock")); |
| 356 | if (lock_fd < 0) |
| 357 | return _error->Error(_("Unable to lock the download directory")); |
| 358 | Lock.Fd(lock_fd); |
| 359 | } |
| 360 | |
| 361 | CacheFile Cache; |
| 362 | if (Cache.Open() == false) |
| 363 | return false; |
| 364 | |
| 365 | LogCleaner Cleaner; |
| 366 | |
| 367 | return Cleaner.Go(archivedir, *Cache) && |
| 368 | Cleaner.Go(flCombine(archivedir, "partial/"), *Cache); |
| 369 | } |
| 370 | /*}}}*/ |