dpkgpm.cc 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322
  1. // -*- mode: cpp; mode: fold -*-
  2. // Description /*{{{*/
  3. // $Id: dpkgpm.cc,v 1.12 1999/07/26 17:46:08 jgg Exp $
  4. /* ######################################################################
  5. DPKG Package Manager - Provide an interface to dpkg
  6. ##################################################################### */
  7. /*}}}*/
  8. // Includes /*{{{*/
  9. #ifdef __GNUG__
  10. #pragma implementation "apt-pkg/dpkgpm.h"
  11. #endif
  12. #include <apt-pkg/dpkgpm.h>
  13. #include <apt-pkg/error.h>
  14. #include <apt-pkg/configuration.h>
  15. #include <unistd.h>
  16. #include <stdlib.h>
  17. #include <fcntl.h>
  18. #include <sys/types.h>
  19. #include <sys/wait.h>
  20. #include <signal.h>
  21. #include <errno.h>
  22. /*}}}*/
  23. // DPkgPM::pkgDPkgPM - Constructor /*{{{*/
  24. // ---------------------------------------------------------------------
  25. /* */
  26. pkgDPkgPM::pkgDPkgPM(pkgDepCache &Cache) : pkgPackageManager(Cache)
  27. {
  28. }
  29. /*}}}*/
  30. // DPkgPM::pkgDPkgPM - Destructor /*{{{*/
  31. // ---------------------------------------------------------------------
  32. /* */
  33. pkgDPkgPM::~pkgDPkgPM()
  34. {
  35. }
  36. /*}}}*/
  37. // DPkgPM::Install - Install a package /*{{{*/
  38. // ---------------------------------------------------------------------
  39. /* Add an install operation to the sequence list */
  40. bool pkgDPkgPM::Install(PkgIterator Pkg,string File)
  41. {
  42. if (File.empty() == true || Pkg.end() == true)
  43. return _error->Error("Internal Error, No file name for %s",Pkg.Name());
  44. List.push_back(Item(Item::Install,Pkg,File));
  45. return true;
  46. }
  47. /*}}}*/
  48. // DPkgPM::Configure - Configure a package /*{{{*/
  49. // ---------------------------------------------------------------------
  50. /* Add a configure operation to the sequence list */
  51. bool pkgDPkgPM::Configure(PkgIterator Pkg)
  52. {
  53. if (Pkg.end() == true)
  54. return false;
  55. List.push_back(Item(Item::Configure,Pkg));
  56. return true;
  57. }
  58. /*}}}*/
  59. // DPkgPM::Remove - Remove a package /*{{{*/
  60. // ---------------------------------------------------------------------
  61. /* Add a remove operation to the sequence list */
  62. bool pkgDPkgPM::Remove(PkgIterator Pkg,bool Purge)
  63. {
  64. if (Pkg.end() == true)
  65. return false;
  66. if (Purge == true)
  67. List.push_back(Item(Item::Purge,Pkg));
  68. else
  69. List.push_back(Item(Item::Remove,Pkg));
  70. return true;
  71. }
  72. /*}}}*/
  73. // DPkgPM::RunScripts - Run a set of scripts /*{{{*/
  74. // ---------------------------------------------------------------------
  75. /* This looks for a list of script sto run from the configuration file,
  76. each one is run with system from a forked child. */
  77. bool pkgDPkgPM::RunScripts(const char *Cnf)
  78. {
  79. Configuration::Item const *Opts = _config->Tree(Cnf);
  80. if (Opts == 0 || Opts->Child == 0)
  81. return true;
  82. Opts = Opts->Child;
  83. // Fork for running the system calls
  84. pid_t Child = ExecFork();
  85. // This is the child
  86. if (Child == 0)
  87. {
  88. if (chdir("/tmp/") != 0)
  89. _exit(100);
  90. unsigned int Count = 1;
  91. for (; Opts != 0; Opts = Opts->Next, Count++)
  92. {
  93. if (Opts->Value.empty() == true)
  94. continue;
  95. if (system(Opts->Value.c_str()) != 0)
  96. _exit(100+Count);
  97. }
  98. _exit(0);
  99. }
  100. // Wait for the child
  101. int Status = 0;
  102. while (waitpid(Child,&Status,0) != Child)
  103. {
  104. if (errno == EINTR)
  105. continue;
  106. return _error->Errno("waitpid","Couldn't wait for subprocess");
  107. }
  108. // Restore sig int/quit
  109. signal(SIGQUIT,SIG_DFL);
  110. signal(SIGINT,SIG_DFL);
  111. // Check for an error code.
  112. if (WIFEXITED(Status) == 0 || WEXITSTATUS(Status) != 0)
  113. {
  114. unsigned int Count = WEXITSTATUS(Status);
  115. if (Count > 100)
  116. {
  117. Count -= 100;
  118. for (; Opts != 0 && Count != 1; Opts = Opts->Next, Count--);
  119. _error->Error("Problem executing scripts %s '%s'",Cnf,Opts->Value.c_str());
  120. }
  121. return _error->Error("Sub-process returned an error code");
  122. }
  123. return true;
  124. }
  125. /*}}}*/
  126. // DPkgPM::Go - Run the sequence /*{{{*/
  127. // ---------------------------------------------------------------------
  128. /* This globs the operations and calls dpkg */
  129. bool pkgDPkgPM::Go()
  130. {
  131. if (RunScripts("DPkg::Pre-Invoke") == false)
  132. return false;
  133. for (vector<Item>::iterator I = List.begin(); I != List.end();)
  134. {
  135. vector<Item>::iterator J = I;
  136. for (; J != List.end() && J->Op == I->Op; J++);
  137. // Generate the argument list
  138. const char *Args[400];
  139. if (J - I > 350)
  140. J = I + 350;
  141. unsigned int n = 0;
  142. unsigned long Size = 0;
  143. Args[n++] = _config->Find("Dir::Bin::dpkg","dpkg").c_str();
  144. Size += strlen(Args[n-1]);
  145. // Stick in any custom dpkg options
  146. Configuration::Item const *Opts = _config->Tree("DPkg::Options");
  147. if (Opts != 0)
  148. {
  149. Opts = Opts->Child;
  150. for (; Opts != 0; Opts = Opts->Next)
  151. {
  152. if (Opts->Value.empty() == true)
  153. continue;
  154. Args[n++] = Opts->Value.c_str();
  155. Size += Opts->Value.length();
  156. }
  157. }
  158. switch (I->Op)
  159. {
  160. case Item::Remove:
  161. Args[n++] = "--force-depends";
  162. Size += strlen(Args[n-1]);
  163. Args[n++] = "--force-remove-essential";
  164. Size += strlen(Args[n-1]);
  165. Args[n++] = "--remove";
  166. Size += strlen(Args[n-1]);
  167. break;
  168. case Item::Purge:
  169. Args[n++] = "--force-depends";
  170. Size += strlen(Args[n-1]);
  171. Args[n++] = "--force-remove-essential";
  172. Size += strlen(Args[n-1]);
  173. Args[n++] = "--purge";
  174. Size += strlen(Args[n-1]);
  175. break;
  176. case Item::Configure:
  177. Args[n++] = "--configure";
  178. Size += strlen(Args[n-1]);
  179. break;
  180. case Item::Install:
  181. Args[n++] = "--unpack";
  182. Size += strlen(Args[n-1]);
  183. break;
  184. }
  185. // Write in the file or package names
  186. if (I->Op == Item::Install)
  187. {
  188. for (;I != J && Size < 1024; I++)
  189. {
  190. if (I->File[0] != '/')
  191. return _error->Error("Internal Error, Pathname to install is not absolute '%s'",I->File.c_str());
  192. Args[n++] = I->File.c_str();
  193. Size += strlen(Args[n-1]);
  194. }
  195. }
  196. else
  197. {
  198. for (;I != J && Size < 1024; I++)
  199. {
  200. Args[n++] = I->Pkg.Name();
  201. Size += strlen(Args[n-1]);
  202. }
  203. }
  204. Args[n] = 0;
  205. J = I;
  206. if (_config->FindB("Debug::pkgDPkgPM",false) == true)
  207. {
  208. for (unsigned int k = 0; k != n; k++)
  209. clog << Args[k] << ' ';
  210. clog << endl;
  211. continue;
  212. }
  213. cout << flush;
  214. clog << flush;
  215. cerr << flush;
  216. /* Mask off sig int/quit. We do this because dpkg also does when
  217. it forks scripts. What happens is that when you hit ctrl-c it sends
  218. it to all processes in the group. Since dpkg ignores the signal
  219. it doesn't die but we do! So we must also ignore it */
  220. signal(SIGQUIT,SIG_IGN);
  221. signal(SIGINT,SIG_IGN);
  222. // Fork dpkg
  223. pid_t Child = ExecFork();
  224. // This is the child
  225. if (Child == 0)
  226. {
  227. if (chdir(_config->FindDir("DPkg::Run-Directory","/").c_str()) != 0)
  228. _exit(100);
  229. int Flags,dummy;
  230. if ((Flags = fcntl(STDIN_FILENO,F_GETFL,dummy)) < 0)
  231. _exit(100);
  232. // Discard everything in stdin before forking dpkg
  233. if (fcntl(STDIN_FILENO,F_SETFL,Flags | O_NONBLOCK) < 0)
  234. _exit(100);
  235. while (read(STDIN_FILENO,&dummy,1) == 1);
  236. if (fcntl(STDIN_FILENO,F_SETFL,Flags & (~(long)O_NONBLOCK)) < 0)
  237. _exit(100);
  238. /* No Job Control Stop Env is a magic dpkg var that prevents it
  239. from using sigstop */
  240. setenv("DPKG_NO_TSTP","yes",1);
  241. execvp(Args[0],(char **)Args);
  242. cerr << "Could not exec dpkg!" << endl;
  243. _exit(100);
  244. }
  245. // Wait for dpkg
  246. int Status = 0;
  247. while (waitpid(Child,&Status,0) != Child)
  248. {
  249. if (errno == EINTR)
  250. continue;
  251. RunScripts("DPkg::Post-Invoke");
  252. return _error->Errno("waitpid","Couldn't wait for subprocess");
  253. }
  254. // Restore sig int/quit
  255. signal(SIGQUIT,SIG_DFL);
  256. signal(SIGINT,SIG_DFL);
  257. // Check for an error code.
  258. if (WIFEXITED(Status) == 0 || WEXITSTATUS(Status) != 0)
  259. {
  260. RunScripts("DPkg::Post-Invoke");
  261. if (WIFSIGNALED(Status) != 0 && WTERMSIG(Status) == SIGSEGV)
  262. return _error->Error("Sub-process recieved a segmentation fault.");
  263. if (WIFEXITED(Status) != 0)
  264. return _error->Error("Sub-process returned an error code (%u)",WEXITSTATUS(Status));
  265. return _error->Error("Sub-process exited unexpectedly");
  266. }
  267. }
  268. if (RunScripts("DPkg::Post-Invoke") == false)
  269. return false;
  270. return true;
  271. }
  272. /*}}}*/
  273. // pkgDpkgPM::Reset - Dump the contents of the command list /*{{{*/
  274. // ---------------------------------------------------------------------
  275. /* */
  276. void pkgDPkgPM::Reset()
  277. {
  278. List.erase(List.begin(),List.end());
  279. }
  280. /*}}}*/