apt  2.2.4
About: Apt (Advanced Package Tool) is a management system for software packages (Debian/Ubuntu). Release series 2.2.
  Fossies Dox: apt-2.2.4.tar.gz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

apt-helper.cc
Go to the documentation of this file.
1 // -*- mode: cpp; mode: fold -*-
2 // Description /*{{{*/
3 /* #####################################################################
4  apt-helper - cmdline helpers
5  ##################################################################### */
6  /*}}}*/
7 // Include Files /*{{{*/
8 #include <config.h>
9 
10 #include <apt-pkg/acquire-item.h>
11 #include <apt-pkg/acquire.h>
12 #include <apt-pkg/cmndline.h>
14 #include <apt-pkg/configuration.h>
15 #include <apt-pkg/error.h>
16 #include <apt-pkg/fileutl.h>
17 #include <apt-pkg/init.h>
18 #include <apt-pkg/pkgsystem.h>
19 #include <apt-pkg/proxy.h>
20 #include <apt-pkg/strutl.h>
21 
22 #include <apt-pkg/srvrec.h>
28 
29 #include <iostream>
30 #include <string>
31 #include <vector>
32 
33 #include <stdlib.h>
34 #include <sys/types.h>
35 #include <sys/wait.h>
36 #include <unistd.h>
37 
38 #include <apti18n.h>
39  /*}}}*/
40 
41 static bool DoAutoDetectProxy(CommandLine &CmdL) /*{{{*/
42 {
43  if (CmdL.FileSize() != 2)
44  return _error->Error(_("Need one URL as argument"));
45  URI ServerURL(CmdL.FileList[1]);
46  if (AutoDetectProxy(ServerURL) == false)
47  return false;
48  std::string SpecificProxy = _config->Find("Acquire::"+ServerURL.Access+"::Proxy::" + ServerURL.Host);
49  ioprintf(std::cout, "Using proxy '%s' for URL '%s'\n",
50  SpecificProxy.c_str(), std::string(ServerURL).c_str());
51 
52  return true;
53 }
54  /*}}}*/
55 static bool DoDownloadFile(CommandLine &CmdL) /*{{{*/
56 {
57  if (CmdL.FileSize() <= 2)
58  return _error->Error(_("Must specify at least one pair url/filename"));
59 
61  size_t fileind = 0;
62  std::vector<std::string> targetfiles;
63  while (fileind + 2 <= CmdL.FileSize())
64  {
65  std::string download_uri = CmdL.FileList[fileind + 1];
66  std::string targetfile = CmdL.FileList[fileind + 2];
67  HashStringList hashes;
68 
69  fileind += 2;
70 
71  // An empty string counts as a hash for compatibility reasons
72  if (CmdL.FileSize() > fileind + 1 && *CmdL.FileList[fileind + 1] == '\0')
73  fileind++;
74 
75  /* Let's start looking for hashes */
76  for (auto i = fileind + 1; CmdL.FileSize() > i; i++)
77  {
78  bool isAHash = false;
79 
80  for (auto HashP = HashString::SupportedHashes(); *HashP != nullptr; HashP++)
81  {
82  if (APT::String::Startswith(CmdL.FileList[i], *HashP))
83  isAHash = true;
84  }
85 
86  if (!isAHash)
87  break;
88 
89  hashes.push_back(HashString(CmdL.FileList[i]));
90  fileind++;
91  }
92 
93  // we use download_uri as descr and targetfile as short-descr
94  new pkgAcqFile(&Fetcher, download_uri, hashes, 0, download_uri, targetfile,
95  "dest-dir-ignored", targetfile);
96  targetfiles.push_back(targetfile);
97  }
98 
99  bool Failed = false;
100  if (AcquireRun(Fetcher, 0, &Failed, NULL) == false || Failed == true)
101  return _error->Error(_("Download Failed"));
102  if (targetfiles.empty() == false)
103  for (std::vector<std::string>::const_iterator f = targetfiles.begin(); f != targetfiles.end(); ++f)
104  if (FileExists(*f) == false)
105  return _error->Error(_("Download Failed"));
106 
107  return true;
108 }
109  /*}}}*/
110 static bool DoSrvLookup(CommandLine &CmdL) /*{{{*/
111 {
112  if (CmdL.FileSize() <= 1)
113  return _error->Error("Must specify at least one SRV record");
114 
115  for(size_t i = 1; CmdL.FileList[i] != NULL; ++i)
116  {
117  std::vector<SrvRec> srv_records;
118  std::string const name = CmdL.FileList[i];
119  c0out << "# Target\tPriority\tWeight\tPort # for " << name << std::endl;
120  size_t const found = name.find(":");
121  if (found != std::string::npos)
122  {
123  std::string const host = name.substr(0, found);
124  size_t const port = atoi(name.c_str() + found + 1);
125  if(GetSrvRecords(host, port, srv_records) == false)
126  _error->Error(_("GetSrvRec failed for %s"), name.c_str());
127  }
128  else if(GetSrvRecords(name, srv_records) == false)
129  _error->Error(_("GetSrvRec failed for %s"), name.c_str());
130 
131  for (SrvRec const &I : srv_records)
132  ioprintf(c1out, "%s\t%d\t%d\t%d\n", I.target.c_str(), I.priority, I.weight, I.port);
133  }
134  return true;
135 }
136  /*}}}*/
137 static const APT::Configuration::Compressor *FindCompressor(std::vector<APT::Configuration::Compressor> const &compressors, std::string const &name) /*{{{*/
138 {
139  APT::Configuration::Compressor const * compressor = NULL;
140  for (auto const & c : compressors)
141  {
142  if (compressor != NULL && c.Cost >= compressor->Cost)
143  continue;
144  if (c.Name == name || c.Extension == name || (!c.Extension.empty() && c.Extension.substr(1) == name))
145  compressor = &c;
146  }
147 
148  return compressor;
149 }
150  /*}}}*/
151 static bool DoCatFile(CommandLine &CmdL) /*{{{*/
152 {
153  FileFd fd;
154  FileFd out;
155  std::string const compressorName = _config->Find("Apt-Helper::Cat-File::Compress", "");
156 
157  if (compressorName.empty() == false)
158  {
159 
160  auto const compressors = APT::Configuration::getCompressors();
161  auto const compressor = FindCompressor(compressors, compressorName);
162 
163  if (compressor == NULL)
164  return _error->Error("Could not find compressor: %s", compressorName.c_str());
165 
166  if (out.OpenDescriptor(STDOUT_FILENO, FileFd::WriteOnly, *compressor) == false)
167  return false;
168  } else
169  {
170  if (out.OpenDescriptor(STDOUT_FILENO, FileFd::WriteOnly) == false)
171  return false;
172  }
173 
174  if (CmdL.FileSize() <= 1)
175  {
176  if (fd.OpenDescriptor(STDIN_FILENO, FileFd::ReadOnly) == false)
177  return false;
178  if (CopyFile(fd, out) == false)
179  return false;
180  return true;
181  }
182 
183  for(size_t i = 1; CmdL.FileList[i] != NULL; ++i)
184  {
185  std::string const name = CmdL.FileList[i];
186 
187  if (name != "-")
188  {
189  if (fd.Open(name, FileFd::ReadOnly, FileFd::Extension) == false)
190  return false;
191  }
192  else
193  {
194  if (fd.OpenDescriptor(STDIN_FILENO, FileFd::ReadOnly) == false)
195  return false;
196  }
197 
198  if (CopyFile(fd, out) == false)
199  return false;
200  }
201  return true;
202 }
203  /*}}}*/
204 
205 static pid_t ExecuteProcess(const char *Args[]) /*{{{*/
206 {
207  pid_t pid = ExecFork();
208  if (pid == 0)
209  {
210  execvp(Args[0], (char **)Args);
211  _exit(100);
212  }
213  return pid;
214 }
215 
216 static bool ServiceIsActive(const char *service)
217 {
218  const char *argv[] = {"systemctl", "is-active", "-q", service, nullptr};
219  pid_t pid = ExecuteProcess(argv);
220  return ExecWait(pid, "systemctl is-active", true);
221 }
222 
223 static bool DoWaitOnline(CommandLine &)
224 {
225  // Also add services to After= in .service
226  static const char *WaitingTasks[][6] = {
227  {"systemd-networkd.service", "/lib/systemd/systemd-networkd-wait-online", "-q", "--timeout=30", nullptr},
228  {"NetworkManager.service", "nm-online", "-q", "--timeout", "30", nullptr},
229  {"connman.service", "connmand-wait-online", "--timeout=30", nullptr},
230  };
231 
232  for (const char **task : WaitingTasks)
233  {
234  if (ServiceIsActive(task[0]))
235  {
236  pid_t pid = ExecuteProcess(task + 1);
237 
238  ExecWait(pid, task[1]);
239  }
240  }
241 
242  return _error->PendingError() == false;
243 }
244  /*}}}*/
245 static bool DropPrivsAndRun(CommandLine &CmdL) /*{{{*/
246 {
247  if (CmdL.FileSize() < 2)
248  return _error->Error("No command given to run without privileges");
249  if (DropPrivileges() == false)
250  return _error->Error("Dropping Privileges failed, not executing '%s'", CmdL.FileList[1]);
251 
252  std::vector<char const *> Args;
253  Args.reserve(CmdL.FileSize() + 1);
254  for (auto a = CmdL.FileList + 1; *a != nullptr; ++a)
255  Args.push_back(*a);
256  Args.push_back(nullptr);
257  auto const pid = ExecuteProcess(Args.data());
258  return ExecWait(pid, CmdL.FileList[1]);
259 }
260  /*}}}*/
261 static bool AnalyzePattern(CommandLine &CmdL) /*{{{*/
262 {
263  if (CmdL.FileSize() != 2)
264  return _error->Error("Expect one argument, a pattern");
265 
266  try
267  {
268  auto top = APT::Internal::PatternTreeParser(CmdL.FileList[1]).parseTop();
269  top->render(std::cout) << "\n";
270  }
272  {
273  std::stringstream ss;
274  ss << "input:" << e.location.start << "-" << e.location.end << ": error: " << e.message << "\n";
275  ss << CmdL.FileList[1] << "\n";
276  for (size_t i = 0; i < e.location.start; i++)
277  ss << " ";
278  for (size_t i = e.location.start; i < e.location.end; i++)
279  ss << "^";
280 
281  ss << "\n";
282 
283  _error->Error("%s", ss.str().c_str());
284  return false;
285  }
286 
287  return true;
288 }
289  /*}}}*/
290 static bool DoQuoteString(CommandLine &CmdL) /*{{{*/
291 {
292  if (CmdL.FileSize() != 3)
293  return _error->Error("Expect two arguments, a string to quote and a string of additional characters to quote");
294  std::cout << QuoteString(CmdL.FileList[1], CmdL.FileList[2]) << '\n';
295  return true;
296 }
297  /*}}}*/
298 static bool ShowHelp(CommandLine &) /*{{{*/
299 {
300  std::cout <<
301  _("Usage: apt-helper [options] command\n"
302  " apt-helper [options] cat-file file ...\n"
303  " apt-helper [options] download-file uri target-path\n"
304  "\n"
305  "apt-helper bundles a variety of commands for shell scripts to use\n"
306  "e.g. the same proxy configuration or acquire system as APT would.\n");
307  return true;
308 }
309  /*}}}*/
310 static std::vector<aptDispatchWithHelp> GetCommands() /*{{{*/
311 {
312  return {
313  {"download-file", &DoDownloadFile, _("download the given uri to the target-path")},
314  {"srv-lookup", &DoSrvLookup, _("lookup a SRV record (e.g. _http._tcp.ftp.debian.org)")},
315  {"cat-file", &DoCatFile, _("concatenate files, with automatic decompression")},
316  {"auto-detect-proxy", &DoAutoDetectProxy, _("detect proxy using apt.conf")},
317  {"wait-online", &DoWaitOnline, _("wait for system to be online")},
318  {"drop-privs", &DropPrivsAndRun, _("drop privileges before running given command")},
319  {"analyze-pattern", &AnalyzePattern, _("analyse a pattern")},
320  {"analyse-pattern", &AnalyzePattern, nullptr},
321  {"quote-string", &DoQuoteString, nullptr},
322  {nullptr, nullptr, nullptr}};
323 }
324  /*}}}*/
325 int main(int argc,const char *argv[]) /*{{{*/
326 {
327  CommandLine CmdL;
328  auto const Cmds = ParseCommandLine(CmdL, APT_CMD::APT_HELPER, &_config, &_system, argc, argv, &ShowHelp, &GetCommands);
329 
330  InitOutput();
331 
332  return DispatchCommandLine(CmdL, Cmds);
333 }
334  /*}}}*/
static bool std::string const metaIndex const *const pkgAcqMetaClearSig *const pkgAcquire::Item *const I
static bool ShowHelp(CommandLine &)
Definition: apt-helper.cc:298
static std::vector< aptDispatchWithHelp > GetCommands()
Definition: apt-helper.cc:310
static bool DoAutoDetectProxy(CommandLine &CmdL)
Definition: apt-helper.cc:41
static bool DoQuoteString(CommandLine &CmdL)
Definition: apt-helper.cc:290
static pid_t ExecuteProcess(const char *Args[])
Definition: apt-helper.cc:205
static bool ServiceIsActive(const char *service)
Definition: apt-helper.cc:216
static bool DoSrvLookup(CommandLine &CmdL)
Definition: apt-helper.cc:110
static const APT::Configuration::Compressor * FindCompressor(std::vector< APT::Configuration::Compressor > const &compressors, std::string const &name)
Definition: apt-helper.cc:137
int main(int argc, const char *argv[])
Definition: apt-helper.cc:325
static bool DoDownloadFile(CommandLine &CmdL)
Definition: apt-helper.cc:55
static bool DoWaitOnline(CommandLine &)
Definition: apt-helper.cc:223
static bool AnalyzePattern(CommandLine &CmdL)
Definition: apt-helper.cc:261
static bool DoCatFile(CommandLine &CmdL)
Definition: apt-helper.cc:151
static bool DropPrivsAndRun(CommandLine &CmdL)
Definition: apt-helper.cc:245
const char ** FileList
Definition: cmndline.h:78
unsigned int FileSize() const APT_PURE
Definition: cmndline.cc:353
std::string Find(const char *Name, const char *Default=0) const
Definition: fileutl.h:39
bool OpenDescriptor(int Fd, unsigned int const Mode, CompressMode Compress, bool AutoClose=false)
Definition: fileutl.cc:2572
@ Extension
Definition: fileutl.h:80
@ WriteOnly
Definition: fileutl.h:60
@ ReadOnly
Definition: fileutl.h:59
bool Open(std::string FileName, unsigned int const Mode, CompressMode Compress, unsigned long const AccessMode=0666)
Definition: fileutl.cc:2415
bool push_back(const HashString &hashString)
Definition: hashes.cc:232
static APT_PURE const char ** SupportedHashes()
Definition: hashes.cc:135
Definition: srvrec.h:19
Definition: strutl.h:193
std::string Access
Definition: strutl.h:198
std::string Host
Definition: strutl.h:201
Retrieve an arbitrary file to the current directory. {{{.
Configuration * _config
bool ExecWait(pid_t Pid, const char *Name, bool Reap)
Definition: fileutl.cc:942
bool FileExists(string File)
Definition: fileutl.cc:326
bool DropPrivileges()
Drop privileges.
Definition: fileutl.cc:3260
bool CopyFile(FileFd &From, FileFd &To)
Definition: fileutl.cc:164
pid_t ExecFork()
Definition: fileutl.cc:881
APT_PUBLIC std::vector< Compressor > const getCompressors(bool const Cached=true)
Return a vector of Compressors supported for data.tar's.
bool Startswith(const std::string &s, const std::string &start)
Definition: strutl.cc:84
pkgSystem * _system
Definition: pkgsystem.cc:24
std::vector< CommandLine::Dispatch > ParseCommandLine(CommandLine &CmdL, APT_CMD const Binary, Configuration *const *const Cnf, pkgSystem **const Sys, int const argc, const char *argv[], bool(*ShowHelp)(CommandLine &), std::vector< aptDispatchWithHelp >(*GetCommands)(void))
unsigned short DispatchCommandLine(CommandLine &CmdL, std::vector< CommandLine::Dispatch > const &Cmds)
bool AcquireRun(pkgAcquire &Fetcher, int const PulseInterval, bool *const Failure, bool *const TransientNetworkFailure)
bool InitOutput(std::basic_streambuf< char > *const out)
APT_PUBLIC std::ostream c1out
APT_PUBLIC std::ostream c0out
bool AutoDetectProxy(URI &URL)
Definition: proxy.cc:33
bool GetSrvRecords(std::string host, int port, std::vector< SrvRec > &Result)
Get SRV records for query string like: _http._tcp.example.com.
Definition: srvrec.cc:35
Representation of supported compressors.
PatternTreeParser parses the given sentence into a parse tree.
std::unique_ptr< Node > parseTop()
Parse a complete pattern.
void ioprintf(ostream &out, const char *format,...)
Definition: strutl.cc:1433
string QuoteString(const string &Str, const char *Bad)
Definition: strutl.cc:384