dpkgpm.cc 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328
  1. // -*- mode: cpp; mode: fold -*-
  2. // Description /*{{{*/
  3. // $Id: dpkgpm.cc,v 1.8 1999/03/05 19:36:49 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)
  63. {
  64. if (Pkg.end() == true)
  65. return false;
  66. List.push_back(Item(Item::Remove,Pkg));
  67. return true;
  68. }
  69. /*}}}*/
  70. // DPkgPM::RunScripts - Run a set of scripts /*{{{*/
  71. // ---------------------------------------------------------------------
  72. /* This looks for a list of script sto run from the configuration file,
  73. each one is run with system from a forked child. */
  74. bool pkgDPkgPM::RunScripts(const char *Cnf)
  75. {
  76. Configuration::Item const *Opts = _config->Tree(Cnf);
  77. if (Opts == 0 || Opts->Child == 0)
  78. return true;
  79. Opts = Opts->Child;
  80. // Fork for running the system calls
  81. pid_t Child = fork();
  82. if (Child < 0)
  83. return _error->Errno("fork","Could't fork");
  84. // This is the child
  85. if (Child == 0)
  86. {
  87. signal(SIGPIPE,SIG_DFL);
  88. signal(SIGQUIT,SIG_DFL);
  89. signal(SIGINT,SIG_DFL);
  90. signal(SIGWINCH,SIG_DFL);
  91. signal(SIGCONT,SIG_DFL);
  92. signal(SIGTSTP,SIG_DFL);
  93. if (chdir("/tmp/") != 0)
  94. _exit(100);
  95. // Close all of our FDs - just in case
  96. for (int K = 3; K != 40; K++)
  97. fcntl(K,F_SETFD,FD_CLOEXEC);
  98. unsigned int Count = 1;
  99. for (; Opts != 0; Opts = Opts->Next, Count++)
  100. {
  101. if (Opts->Value.empty() == true)
  102. continue;
  103. if (system(Opts->Value.c_str()) != 0)
  104. _exit(100+Count);
  105. }
  106. _exit(0);
  107. }
  108. // Wait for the child
  109. int Status = 0;
  110. while (waitpid(Child,&Status,0) != Child)
  111. {
  112. if (errno == EINTR)
  113. continue;
  114. return _error->Errno("waitpid","Couldn't wait for subprocess");
  115. }
  116. // Restore sig int/quit
  117. signal(SIGQUIT,SIG_DFL);
  118. signal(SIGINT,SIG_DFL);
  119. // Check for an error code.
  120. if (WIFEXITED(Status) == 0 || WEXITSTATUS(Status) != 0)
  121. {
  122. unsigned int Count = WEXITSTATUS(Status);
  123. if (Count > 100)
  124. {
  125. Count -= 100;
  126. for (; Opts != 0 && Count != 1; Opts = Opts->Next, Count--);
  127. _error->Error("Problem executing scripts %s '%s'",Cnf,Opts->Value.c_str());
  128. }
  129. return _error->Error("Sub-process returned an error code");
  130. }
  131. return true;
  132. }
  133. /*}}}*/
  134. // DPkgPM::Go - Run the sequence /*{{{*/
  135. // ---------------------------------------------------------------------
  136. /* This globs the operations and calls dpkg */
  137. bool pkgDPkgPM::Go()
  138. {
  139. if (RunScripts("DPkg::Pre-Invoke") == false)
  140. return false;
  141. for (vector<Item>::iterator I = List.begin(); I != List.end();)
  142. {
  143. vector<Item>::iterator J = I;
  144. for (; J != List.end() && J->Op == I->Op; J++);
  145. // Generate the argument list
  146. const char *Args[400];
  147. if (J - I > 350)
  148. J = I + 350;
  149. unsigned int n = 0;
  150. unsigned long Size = 0;
  151. Args[n++] = _config->Find("Dir::Bin::dpkg","dpkg").c_str();
  152. Size += strlen(Args[n-1]);
  153. // Stick in any custom dpkg options
  154. Configuration::Item const *Opts = _config->Tree("DPkg::Options");
  155. if (Opts != 0)
  156. {
  157. Opts = Opts->Child;
  158. for (; Opts != 0; Opts = Opts->Next)
  159. {
  160. if (Opts->Value.empty() == true)
  161. continue;
  162. Args[n++] = Opts->Value.c_str();
  163. Size += Opts->Value.length();
  164. }
  165. }
  166. switch (I->Op)
  167. {
  168. case Item::Remove:
  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++] = "--remove";
  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 = fork();
  224. if (Child < 0)
  225. return _error->Errno("fork","Could't fork");
  226. // This is the child
  227. if (Child == 0)
  228. {
  229. signal(SIGPIPE,SIG_DFL);
  230. signal(SIGQUIT,SIG_DFL);
  231. signal(SIGINT,SIG_DFL);
  232. signal(SIGWINCH,SIG_DFL);
  233. signal(SIGCONT,SIG_DFL);
  234. signal(SIGTSTP,SIG_DFL);
  235. if (chdir(_config->FindDir("DPkg::Run-Directory","/").c_str()) != 0)
  236. _exit(100);
  237. // Close all of our FDs - just in case
  238. for (int K = 3; K != 40; K++)
  239. fcntl(K,F_SETFD,FD_CLOEXEC);
  240. int Flags,dummy;
  241. if ((Flags = fcntl(STDIN_FILENO,F_GETFL,dummy)) < 0)
  242. _exit(100);
  243. // Discard everything in stdin before forking dpkg
  244. if (fcntl(STDIN_FILENO,F_SETFL,Flags | O_NONBLOCK) < 0)
  245. _exit(100);
  246. while (read(STDIN_FILENO,&dummy,1) == 1);
  247. if (fcntl(STDIN_FILENO,F_SETFL,Flags & (~(long)O_NONBLOCK)) < 0)
  248. _exit(100);
  249. /* No Job Control Stop Env is a magic dpkg var that prevents it
  250. from using sigstop */
  251. setenv("DPKG_NO_TSTP","yes",1);
  252. execvp(Args[0],(char **)Args);
  253. cerr << "Could not exec dpkg!" << endl;
  254. _exit(100);
  255. }
  256. // Wait for dpkg
  257. int Status = 0;
  258. while (waitpid(Child,&Status,0) != Child)
  259. {
  260. if (errno == EINTR)
  261. continue;
  262. RunScripts("DPkg::Post-Invoke");
  263. return _error->Errno("waitpid","Couldn't wait for subprocess");
  264. }
  265. // Restore sig int/quit
  266. signal(SIGQUIT,SIG_DFL);
  267. signal(SIGINT,SIG_DFL);
  268. // Check for an error code.
  269. if (WIFEXITED(Status) == 0 || WEXITSTATUS(Status) != 0)
  270. {
  271. RunScripts("DPkg::Post-Invoke");
  272. if (WIFSIGNALED(Status) != 0 && WTERMSIG(Status) == SIGSEGV)
  273. return _error->Error("Sub-process recieved a segmentation fault.");
  274. if (WIFEXITED(Status) != 0)
  275. return _error->Error("Sub-process returned an error code (%u)",WEXITSTATUS(Status));
  276. return _error->Error("Sub-process exited unexpectedly");
  277. }
  278. }
  279. if (RunScripts("DPkg::Post-Invoke") == false)
  280. return false;
  281. return true;
  282. }
  283. /*}}}*/