]> git.saurik.com Git - apt-legacy.git/blob - apt-pkg/deb/dpkgpm.cc.orig
Fix compilation of http when embedding into Cydia.
[apt-legacy.git] / apt-pkg / deb / dpkgpm.cc.orig
1 // -*- mode: cpp; mode: fold -*-
2 // Description /*{{{*/
3 // $Id: dpkgpm.cc,v 1.28 2004/01/27 02:25:01 mdz Exp $
4 /* ######################################################################
5
6 DPKG Package Manager - Provide an interface to dpkg
7
8 ##################################################################### */
9 /*}}}*/
10 // Includes /*{{{*/
11 #include <apt-pkg/dpkgpm.h>
12 #include <apt-pkg/error.h>
13 #include <apt-pkg/configuration.h>
14 #include <apt-pkg/depcache.h>
15 #include <apt-pkg/strutl.h>
16 #include <apti18n.h>
17 #include <apt-pkg/fileutl.h>
18
19 #include <unistd.h>
20 #include <stdlib.h>
21 #include <fcntl.h>
22 #include <sys/select.h>
23 #include <sys/types.h>
24 #include <sys/wait.h>
25 #include <signal.h>
26 #include <errno.h>
27 #include <stdio.h>
28 #include <string.h>
29 #include <algorithm>
30 #include <sstream>
31 #include <map>
32
33 #include <termios.h>
34 #include <unistd.h>
35 #include <sys/ioctl.h>
36 #include <sys/stat.h>
37 #include <util.h>
38
39 #include <config.h>
40 #include <apti18n.h>
41 /*}}}*/
42
43 using namespace std;
44
45 namespace
46 {
47 // Maps the dpkg "processing" info to human readable names. Entry 0
48 // of each array is the key, entry 1 is the value.
49 const std::pair<const char *, const char *> PackageProcessingOps[] = {
50 std::make_pair("install", N_("Installing %s")),
51 std::make_pair("configure", N_("Configuring %s")),
52 std::make_pair("remove", N_("Removing %s")),
53 std::make_pair("purge", N_("Completely removing %s")),
54 std::make_pair("trigproc", N_("Running post-installation trigger %s"))
55 };
56
57 const std::pair<const char *, const char *> * const PackageProcessingOpsBegin = PackageProcessingOps;
58 const std::pair<const char *, const char *> * const PackageProcessingOpsEnd = PackageProcessingOps + sizeof(PackageProcessingOps) / sizeof(PackageProcessingOps[0]);
59
60 // Predicate to test whether an entry in the PackageProcessingOps
61 // array matches a string.
62 class MatchProcessingOp
63 {
64 const char *target;
65
66 public:
67 MatchProcessingOp(const char *the_target)
68 : target(the_target)
69 {
70 }
71
72 bool operator()(const std::pair<const char *, const char *> &pair) const
73 {
74 return strcmp(pair.first, target) == 0;
75 }
76 };
77 }
78
79 /* helper function to ionice the given PID
80
81 there is no C header for ionice yet - just the syscall interface
82 so we use the binary from util-linux
83 */
84 static bool
85 ionice(int PID)
86 {
87 if (!FileExists("/usr/bin/ionice"))
88 return false;
89 pid_t Process = ExecFork();
90 if (Process == 0)
91 {
92 char buf[32];
93 snprintf(buf, sizeof(buf), "-p%d", PID);
94 const char *Args[4];
95 Args[0] = "/usr/bin/ionice";
96 Args[1] = "-c3";
97 Args[2] = buf;
98 Args[3] = 0;
99 execv(Args[0], (char **)Args);
100 }
101 return ExecWait(Process, "ionice");
102 }
103
104 // DPkgPM::pkgDPkgPM - Constructor /*{{{*/
105 // ---------------------------------------------------------------------
106 /* */
107 pkgDPkgPM::pkgDPkgPM(pkgDepCache *Cache)
108 : pkgPackageManager(Cache), dpkgbuf_pos(0),
109 term_out(NULL), PackagesDone(0), PackagesTotal(0)
110 {
111 }
112 /*}}}*/
113 // DPkgPM::pkgDPkgPM - Destructor /*{{{*/
114 // ---------------------------------------------------------------------
115 /* */
116 pkgDPkgPM::~pkgDPkgPM()
117 {
118 }
119 /*}}}*/
120 // DPkgPM::Install - Install a package /*{{{*/
121 // ---------------------------------------------------------------------
122 /* Add an install operation to the sequence list */
123 bool pkgDPkgPM::Install(PkgIterator Pkg,string File)
124 {
125 if (File.empty() == true || Pkg.end() == true)
126 return _error->Error("Internal Error, No file name for %s",Pkg.Name());
127
128 List.push_back(Item(Item::Install,Pkg,File));
129 return true;
130 }
131 /*}}}*/
132 // DPkgPM::Configure - Configure a package /*{{{*/
133 // ---------------------------------------------------------------------
134 /* Add a configure operation to the sequence list */
135 bool pkgDPkgPM::Configure(PkgIterator Pkg)
136 {
137 if (Pkg.end() == true)
138 return false;
139
140 List.push_back(Item(Item::Configure, Pkg));
141
142 // Use triggers for config calls if we configure "smart"
143 // as otherwise Pre-Depends will not be satisfied, see #526774
144 if (_config->FindB("DPkg::TriggersPending", false) == true)
145 List.push_back(Item(Item::TriggersPending, PkgIterator()));
146
147 return true;
148 }
149 /*}}}*/
150 // DPkgPM::Remove - Remove a package /*{{{*/
151 // ---------------------------------------------------------------------
152 /* Add a remove operation to the sequence list */
153 bool pkgDPkgPM::Remove(PkgIterator Pkg,bool Purge)
154 {
155 if (Pkg.end() == true)
156 return false;
157
158 if (Purge == true)
159 List.push_back(Item(Item::Purge,Pkg));
160 else
161 List.push_back(Item(Item::Remove,Pkg));
162 return true;
163 }
164 /*}}}*/
165 // DPkgPM::SendV2Pkgs - Send version 2 package info /*{{{*/
166 // ---------------------------------------------------------------------
167 /* This is part of the helper script communication interface, it sends
168 very complete information down to the other end of the pipe.*/
169 bool pkgDPkgPM::SendV2Pkgs(FILE *F)
170 {
171 fprintf(F,"VERSION 2\n");
172
173 /* Write out all of the configuration directives by walking the
174 configuration tree */
175 const Configuration::Item *Top = _config->Tree(0);
176 for (; Top != 0;)
177 {
178 if (Top->Value.empty() == false)
179 {
180 fprintf(F,"%s=%s\n",
181 QuoteString(Top->FullTag(),"=\"\n").c_str(),
182 QuoteString(Top->Value,"\n").c_str());
183 }
184
185 if (Top->Child != 0)
186 {
187 Top = Top->Child;
188 continue;
189 }
190
191 while (Top != 0 && Top->Next == 0)
192 Top = Top->Parent;
193 if (Top != 0)
194 Top = Top->Next;
195 }
196 fprintf(F,"\n");
197
198 // Write out the package actions in order.
199 for (vector<Item>::iterator I = List.begin(); I != List.end(); I++)
200 {
201 if(I->Pkg.end() == true)
202 continue;
203
204 pkgDepCache::StateCache &S = Cache[I->Pkg];
205
206 fprintf(F,"%s ",I->Pkg.Name());
207 // Current version
208 if (I->Pkg->CurrentVer == 0)
209 fprintf(F,"- ");
210 else
211 fprintf(F,"%s ",I->Pkg.CurrentVer().VerStr());
212
213 // Show the compare operator
214 // Target version
215 if (S.InstallVer != 0)
216 {
217 int Comp = 2;
218 if (I->Pkg->CurrentVer != 0)
219 Comp = S.InstVerIter(Cache).CompareVer(I->Pkg.CurrentVer());
220 if (Comp < 0)
221 fprintf(F,"> ");
222 if (Comp == 0)
223 fprintf(F,"= ");
224 if (Comp > 0)
225 fprintf(F,"< ");
226 fprintf(F,"%s ",S.InstVerIter(Cache).VerStr());
227 }
228 else
229 fprintf(F,"> - ");
230
231 // Show the filename/operation
232 if (I->Op == Item::Install)
233 {
234 // No errors here..
235 if (I->File[0] != '/')
236 fprintf(F,"**ERROR**\n");
237 else
238 fprintf(F,"%s\n",I->File.c_str());
239 }
240 if (I->Op == Item::Configure)
241 fprintf(F,"**CONFIGURE**\n");
242 if (I->Op == Item::Remove ||
243 I->Op == Item::Purge)
244 fprintf(F,"**REMOVE**\n");
245
246 if (ferror(F) != 0)
247 return false;
248 }
249 return true;
250 }
251 /*}}}*/
252 // DPkgPM::RunScriptsWithPkgs - Run scripts with package names on stdin /*{{{*/
253 // ---------------------------------------------------------------------
254 /* This looks for a list of scripts to run from the configuration file
255 each one is run and is fed on standard input a list of all .deb files
256 that are due to be installed. */
257 bool pkgDPkgPM::RunScriptsWithPkgs(const char *Cnf)
258 {
259 Configuration::Item const *Opts = _config->Tree(Cnf);
260 if (Opts == 0 || Opts->Child == 0)
261 return true;
262 Opts = Opts->Child;
263
264 unsigned int Count = 1;
265 for (; Opts != 0; Opts = Opts->Next, Count++)
266 {
267 if (Opts->Value.empty() == true)
268 continue;
269
270 // Determine the protocol version
271 string OptSec = Opts->Value;
272 string::size_type Pos;
273 if ((Pos = OptSec.find(' ')) == string::npos || Pos == 0)
274 Pos = OptSec.length();
275 OptSec = "DPkg::Tools::Options::" + string(Opts->Value.c_str(),Pos);
276
277 unsigned int Version = _config->FindI(OptSec+"::Version",1);
278
279 // Create the pipes
280 int Pipes[2];
281 if (pipe(Pipes) != 0)
282 return _error->Errno("pipe","Failed to create IPC pipe to subprocess");
283 SetCloseExec(Pipes[0],true);
284 SetCloseExec(Pipes[1],true);
285
286 // Purified Fork for running the script
287 pid_t Process = ExecFork();
288 if (Process == 0)
289 {
290 // Setup the FDs
291 dup2(Pipes[0],STDIN_FILENO);
292 SetCloseExec(STDOUT_FILENO,false);
293 SetCloseExec(STDIN_FILENO,false);
294 SetCloseExec(STDERR_FILENO,false);
295
296 const char *Args[4];
297 Args[0] = "/bin/sh";
298 Args[1] = "-c";
299 Args[2] = Opts->Value.c_str();
300 Args[3] = 0;
301 execv(Args[0],(char **)Args);
302 _exit(100);
303 }
304 close(Pipes[0]);
305 FILE *F = fdopen(Pipes[1],"w");
306 if (F == 0)
307 return _error->Errno("fdopen","Faild to open new FD");
308
309 // Feed it the filenames.
310 bool Die = false;
311 if (Version <= 1)
312 {
313 for (vector<Item>::iterator I = List.begin(); I != List.end(); I++)
314 {
315 // Only deal with packages to be installed from .deb
316 if (I->Op != Item::Install)
317 continue;
318
319 // No errors here..
320 if (I->File[0] != '/')
321 continue;
322
323 /* Feed the filename of each package that is pending install
324 into the pipe. */
325 fprintf(F,"%s\n",I->File.c_str());
326 if (ferror(F) != 0)
327 {
328 Die = true;
329 break;
330 }
331 }
332 }
333 else
334 Die = !SendV2Pkgs(F);
335
336 fclose(F);
337
338 // Clean up the sub process
339 if (ExecWait(Process,Opts->Value.c_str()) == false)
340 return _error->Error("Failure running script %s",Opts->Value.c_str());
341 }
342
343 return true;
344 }
345
346 /*}}}*/
347 // DPkgPM::DoStdin - Read stdin and pass to slave pty /*{{{*/
348 // ---------------------------------------------------------------------
349 /*
350 */
351 void pkgDPkgPM::DoStdin(int master)
352 {
353 unsigned char input_buf[256] = {0,};
354 ssize_t len = read(0, input_buf, sizeof(input_buf));
355 if (len)
356 write(master, input_buf, len);
357 else
358 stdin_is_dev_null = true;
359 }
360 /*}}}*/
361 // DPkgPM::DoTerminalPty - Read the terminal pty and write log /*{{{*/
362 // ---------------------------------------------------------------------
363 /*
364 * read the terminal pty and write log
365 */
366 void pkgDPkgPM::DoTerminalPty(int master)
367 {
368 unsigned char term_buf[1024] = {0,0, };
369
370 ssize_t len=read(master, term_buf, sizeof(term_buf));
371 if(len == -1 && errno == EIO)
372 {
373 // this happens when the child is about to exit, we
374 // give it time to actually exit, otherwise we run
375 // into a race
376 usleep(500000);
377 return;
378 }
379 if(len <= 0)
380 return;
381 write(1, term_buf, len);
382 if(term_out)
383 fwrite(term_buf, len, sizeof(char), term_out);
384 }
385 /*}}}*/
386 // DPkgPM::ProcessDpkgStatusBuf /*{{{*/
387 // ---------------------------------------------------------------------
388 /*
389 */
390 void pkgDPkgPM::ProcessDpkgStatusLine(int OutStatusFd, char *line)
391 {
392 bool const Debug = _config->FindB("Debug::pkgDPkgProgressReporting",false);
393 // the status we output
394 ostringstream status;
395
396 if (Debug == true)
397 std::clog << "got from dpkg '" << line << "'" << std::endl;
398
399
400 /* dpkg sends strings like this:
401 'status: <pkg>: <pkg qstate>'
402 errors look like this:
403 'status: /var/cache/apt/archives/krecipes_0.8.1-0ubuntu1_i386.deb : error : trying to overwrite `/usr/share/doc/kde/HTML/en/krecipes/krectip.png', which is also in package krecipes-data
404 and conffile-prompt like this
405 'status: conffile-prompt: conffile : 'current-conffile' 'new-conffile' useredited distedited
406
407 Newer versions of dpkg sent also:
408 'processing: install: pkg'
409 'processing: configure: pkg'
410 'processing: remove: pkg'
411 'processing: purge: pkg' - but for apt is it a ignored "unknown" action
412 'processing: trigproc: trigger'
413
414 */
415 char* list[5];
416 // dpkg sends multiline error messages sometimes (see
417 // #374195 for a example. we should support this by
418 // either patching dpkg to not send multiline over the
419 // statusfd or by rewriting the code here to deal with
420 // it. for now we just ignore it and not crash
421 TokSplitString(':', line, list, sizeof(list)/sizeof(list[0]));
422 if( list[0] == NULL || list[1] == NULL || list[2] == NULL)
423 {
424 if (Debug == true)
425 std::clog << "ignoring line: not enough ':'" << std::endl;
426 return;
427 }
428 const char* const pkg = list[1];
429 const char* action = _strstrip(list[2]);
430
431 // 'processing' from dpkg looks like
432 // 'processing: action: pkg'
433 if(strncmp(list[0], "processing", strlen("processing")) == 0)
434 {
435 char s[200];
436 const char* const pkg_or_trigger = _strstrip(list[2]);
437 action = _strstrip( list[1]);
438 const std::pair<const char *, const char *> * const iter =
439 std::find_if(PackageProcessingOpsBegin,
440 PackageProcessingOpsEnd,
441 MatchProcessingOp(action));
442 if(iter == PackageProcessingOpsEnd)
443 {
444 if (Debug == true)
445 std::clog << "ignoring unknown action: " << action << std::endl;
446 return;
447 }
448 snprintf(s, sizeof(s), _(iter->second), pkg_or_trigger);
449
450 status << "pmstatus:" << pkg_or_trigger
451 << ":" << (PackagesDone/float(PackagesTotal)*100.0)
452 << ":" << s
453 << endl;
454 if(OutStatusFd > 0)
455 write(OutStatusFd, status.str().c_str(), status.str().size());
456 if (Debug == true)
457 std::clog << "send: '" << status.str() << "'" << endl;
458 return;
459 }
460
461 if(strncmp(action,"error",strlen("error")) == 0)
462 {
463 status << "pmerror:" << list[1]
464 << ":" << (PackagesDone/float(PackagesTotal)*100.0)
465 << ":" << list[3]
466 << endl;
467 if(OutStatusFd > 0)
468 write(OutStatusFd, status.str().c_str(), status.str().size());
469 if (Debug == true)
470 std::clog << "send: '" << status.str() << "'" << endl;
471 return;
472 }
473 else if(strncmp(action,"conffile",strlen("conffile")) == 0)
474 {
475 status << "pmconffile:" << list[1]
476 << ":" << (PackagesDone/float(PackagesTotal)*100.0)
477 << ":" << list[3]
478 << endl;
479 if(OutStatusFd > 0)
480 write(OutStatusFd, status.str().c_str(), status.str().size());
481 if (Debug == true)
482 std::clog << "send: '" << status.str() << "'" << endl;
483 return;
484 }
485
486 vector<struct DpkgState> const &states = PackageOps[pkg];
487 const char *next_action = NULL;
488 if(PackageOpsDone[pkg] < states.size())
489 next_action = states[PackageOpsDone[pkg]].state;
490 // check if the package moved to the next dpkg state
491 if(next_action && (strcmp(action, next_action) == 0))
492 {
493 // only read the translation if there is actually a next
494 // action
495 const char *translation = _(states[PackageOpsDone[pkg]].str);
496 char s[200];
497 snprintf(s, sizeof(s), translation, pkg);
498
499 // we moved from one dpkg state to a new one, report that
500 PackageOpsDone[pkg]++;
501 PackagesDone++;
502 // build the status str
503 status << "pmstatus:" << pkg
504 << ":" << (PackagesDone/float(PackagesTotal)*100.0)
505 << ":" << s
506 << endl;
507 if(OutStatusFd > 0)
508 write(OutStatusFd, status.str().c_str(), status.str().size());
509 if (Debug == true)
510 std::clog << "send: '" << status.str() << "'" << endl;
511 }
512 if (Debug == true)
513 std::clog << "(parsed from dpkg) pkg: " << pkg
514 << " action: " << action << endl;
515 }
516 /*}}}*/
517 // DPkgPM::DoDpkgStatusFd /*{{{*/
518 // ---------------------------------------------------------------------
519 /*
520 */
521 void pkgDPkgPM::DoDpkgStatusFd(int statusfd, int OutStatusFd)
522 {
523 char *p, *q;
524 int len;
525
526 len=read(statusfd, &dpkgbuf[dpkgbuf_pos], sizeof(dpkgbuf)-dpkgbuf_pos);
527 dpkgbuf_pos += len;
528 if(len <= 0)
529 return;
530
531 // process line by line if we have a buffer
532 p = q = dpkgbuf;
533 while((q=(char*)memchr(p, '\n', dpkgbuf+dpkgbuf_pos-p)) != NULL)
534 {
535 *q = 0;
536 ProcessDpkgStatusLine(OutStatusFd, p);
537 p=q+1; // continue with next line
538 }
539
540 // now move the unprocessed bits (after the final \n that is now a 0x0)
541 // to the start and update dpkgbuf_pos
542 void *memrchr(void const *, int, size_t);
543 p = (char*)memrchr(dpkgbuf, 0, dpkgbuf_pos);
544 if(p == NULL)
545 return;
546
547 // we are interessted in the first char *after* 0x0
548 p++;
549
550 // move the unprocessed tail to the start and update pos
551 memmove(dpkgbuf, p, p-dpkgbuf);
552 dpkgbuf_pos = dpkgbuf+dpkgbuf_pos-p;
553 }
554 /*}}}*/
555 // DPkgPM::OpenLog /*{{{*/
556 bool pkgDPkgPM::OpenLog()
557 {
558 string logdir = _config->FindDir("Dir::Log");
559 if(not FileExists(logdir))
560 return _error->Error(_("Directory '%s' missing"), logdir.c_str());
561 string logfile_name = flCombine(logdir,
562 _config->Find("Dir::Log::Terminal"));
563 if (!logfile_name.empty())
564 {
565 term_out = fopen(logfile_name.c_str(),"a");
566 if (term_out == NULL)
567 return _error->WarningE(_("Could not open file '%s'"), logfile_name.c_str());
568
569 chmod(logfile_name.c_str(), 0600);
570 // output current time
571 char outstr[200];
572 time_t t = time(NULL);
573 struct tm *tmp = localtime(&t);
574 strftime(outstr, sizeof(outstr), "%F %T", tmp);
575 fprintf(term_out, "\nLog started: %s\n", outstr);
576 }
577 return true;
578 }
579 /*}}}*/
580 // DPkg::CloseLog /*{{{*/
581 bool pkgDPkgPM::CloseLog()
582 {
583 if(term_out)
584 {
585 char outstr[200];
586 time_t t = time(NULL);
587 struct tm *tmp = localtime(&t);
588 strftime(outstr, sizeof(outstr), "%F %T", tmp);
589 fprintf(term_out, "Log ended: ");
590 fprintf(term_out, "%s", outstr);
591 fprintf(term_out, "\n");
592 fclose(term_out);
593 }
594 term_out = NULL;
595 return true;
596 }
597 /*}}}*/
598 /*{{{*/
599 // This implements a racy version of pselect for those architectures
600 // that don't have a working implementation.
601 // FIXME: Probably can be removed on Lenny+1
602 static int racy_pselect(int nfds, fd_set *readfds, fd_set *writefds,
603 fd_set *exceptfds, const struct timespec *timeout,
604 const sigset_t *sigmask)
605 {
606 sigset_t origmask;
607 struct timeval tv;
608 int retval;
609
610 tv.tv_sec = timeout->tv_sec;
611 tv.tv_usec = timeout->tv_nsec/1000;
612
613 sigprocmask(SIG_SETMASK, sigmask, &origmask);
614 retval = select(nfds, readfds, writefds, exceptfds, &tv);
615 sigprocmask(SIG_SETMASK, &origmask, 0);
616 return retval;
617 }
618 /*}}}*/
619 // DPkgPM::Go - Run the sequence /*{{{*/
620 // ---------------------------------------------------------------------
621 /* This globs the operations and calls dpkg
622 *
623 * If it is called with "OutStatusFd" set to a valid file descriptor
624 * apt will report the install progress over this fd. It maps the
625 * dpkg states a package goes through to human readable (and i10n-able)
626 * names and calculates a percentage for each step.
627 */
628 bool pkgDPkgPM::Go(int OutStatusFd)
629 {
630 fd_set rfds;
631 struct timespec tv;
632 sigset_t sigmask;
633 sigset_t original_sigmask;
634
635 unsigned int const MaxArgs = _config->FindI("Dpkg::MaxArgs",8*1024);
636 unsigned int const MaxArgBytes = _config->FindI("Dpkg::MaxArgBytes",32*1024);
637 bool const NoTriggers = _config->FindB("DPkg::NoTriggers", false);
638
639 if (RunScripts("DPkg::Pre-Invoke") == false)
640 return false;
641
642 if (RunScriptsWithPkgs("DPkg::Pre-Install-Pkgs") == false)
643 return false;
644
645 // support subpressing of triggers processing for special
646 // cases like d-i that runs the triggers handling manually
647 bool const SmartConf = (_config->Find("PackageManager::Configure", "all") != "all");
648 bool const TriggersPending = _config->FindB("DPkg::TriggersPending", false);
649 if (_config->FindB("DPkg::ConfigurePending", SmartConf) == true)
650 List.push_back(Item(Item::ConfigurePending, PkgIterator()));
651
652 // map the dpkg states to the operations that are performed
653 // (this is sorted in the same way as Item::Ops)
654 static const struct DpkgState DpkgStatesOpMap[][7] = {
655 // Install operation
656 {
657 {"half-installed", N_("Preparing %s")},
658 {"unpacked", N_("Unpacking %s") },
659 {NULL, NULL}
660 },
661 // Configure operation
662 {
663 {"unpacked",N_("Preparing to configure %s") },
664 {"half-configured", N_("Configuring %s") },
665 { "installed", N_("Installed %s")},
666 {NULL, NULL}
667 },
668 // Remove operation
669 {
670 {"half-configured", N_("Preparing for removal of %s")},
671 {"half-installed", N_("Removing %s")},
672 {"config-files", N_("Removed %s")},
673 {NULL, NULL}
674 },
675 // Purge operation
676 {
677 {"config-files", N_("Preparing to completely remove %s")},
678 {"not-installed", N_("Completely removed %s")},
679 {NULL, NULL}
680 },
681 };
682
683 // init the PackageOps map, go over the list of packages that
684 // that will be [installed|configured|removed|purged] and add
685 // them to the PackageOps map (the dpkg states it goes through)
686 // and the PackageOpsTranslations (human readable strings)
687 for (vector<Item>::const_iterator I = List.begin(); I != List.end();I++)
688 {
689 if((*I).Pkg.end() == true)
690 continue;
691
692 string const name = (*I).Pkg.Name();
693 PackageOpsDone[name] = 0;
694 for(int i=0; (DpkgStatesOpMap[(*I).Op][i]).state != NULL; i++)
695 {
696 PackageOps[name].push_back(DpkgStatesOpMap[(*I).Op][i]);
697 PackagesTotal++;
698 }
699 }
700
701 stdin_is_dev_null = false;
702
703 // create log
704 OpenLog();
705
706 // this loop is runs once per operation
707 for (vector<Item>::const_iterator I = List.begin(); I != List.end();)
708 {
709 // Do all actions with the same Op in one run
710 vector<Item>::const_iterator J = I;
711 if (TriggersPending == true)
712 for (; J != List.end(); J++)
713 {
714 if (J->Op == I->Op)
715 continue;
716 if (J->Op != Item::TriggersPending)
717 break;
718 vector<Item>::const_iterator T = J + 1;
719 if (T != List.end() && T->Op == I->Op)
720 continue;
721 break;
722 }
723 else
724 for (; J != List.end() && J->Op == I->Op; J++)
725 /* nothing */;
726
727 // Generate the argument list
728 const char *Args[MaxArgs + 50];
729
730 // Now check if we are within the MaxArgs limit
731 //
732 // this code below is problematic, because it may happen that
733 // the argument list is split in a way that A depends on B
734 // and they are in the same "--configure A B" run
735 // - with the split they may now be configured in different
736 // runs
737 if (J - I > (signed)MaxArgs)
738 J = I + MaxArgs;
739
740 unsigned int n = 0;
741 unsigned long Size = 0;
742 string const Tmp = _config->Find("Dir::Bin::dpkg","dpkg");
743 Args[n++] = Tmp.c_str();
744 Size += strlen(Args[n-1]);
745
746 // Stick in any custom dpkg options
747 Configuration::Item const *Opts = _config->Tree("DPkg::Options");
748 if (Opts != 0)
749 {
750 Opts = Opts->Child;
751 for (; Opts != 0; Opts = Opts->Next)
752 {
753 if (Opts->Value.empty() == true)
754 continue;
755 Args[n++] = Opts->Value.c_str();
756 Size += Opts->Value.length();
757 }
758 }
759
760 char status_fd_buf[20];
761 int fd[2];
762 pipe(fd);
763
764 Args[n++] = "--status-fd";
765 Size += strlen(Args[n-1]);
766 snprintf(status_fd_buf,sizeof(status_fd_buf),"%i", fd[1]);
767 Args[n++] = status_fd_buf;
768 Size += strlen(Args[n-1]);
769
770 switch (I->Op)
771 {
772 case Item::Remove:
773 Args[n++] = "--force-depends";
774 Size += strlen(Args[n-1]);
775 Args[n++] = "--force-remove-essential";
776 Size += strlen(Args[n-1]);
777 Args[n++] = "--remove";
778 Size += strlen(Args[n-1]);
779 break;
780
781 case Item::Purge:
782 Args[n++] = "--force-depends";
783 Size += strlen(Args[n-1]);
784 Args[n++] = "--force-remove-essential";
785 Size += strlen(Args[n-1]);
786 Args[n++] = "--purge";
787 Size += strlen(Args[n-1]);
788 break;
789
790 case Item::Configure:
791 Args[n++] = "--configure";
792 Size += strlen(Args[n-1]);
793 break;
794
795 case Item::ConfigurePending:
796 Args[n++] = "--configure";
797 Size += strlen(Args[n-1]);
798 Args[n++] = "--pending";
799 Size += strlen(Args[n-1]);
800 break;
801
802 case Item::TriggersPending:
803 Args[n++] = "--triggers-only";
804 Size += strlen(Args[n-1]);
805 Args[n++] = "--pending";
806 Size += strlen(Args[n-1]);
807 break;
808
809 case Item::Install:
810 Args[n++] = "--unpack";
811 Size += strlen(Args[n-1]);
812 Args[n++] = "--auto-deconfigure";
813 Size += strlen(Args[n-1]);
814 break;
815 }
816
817 if (NoTriggers == true && I->Op != Item::TriggersPending &&
818 I->Op != Item::ConfigurePending)
819 {
820 Args[n++] = "--no-triggers";
821 Size += strlen(Args[n-1]);
822 }
823
824 // Write in the file or package names
825 if (I->Op == Item::Install)
826 {
827 for (;I != J && Size < MaxArgBytes; I++)
828 {
829 if (I->File[0] != '/')
830 return _error->Error("Internal Error, Pathname to install is not absolute '%s'",I->File.c_str());
831 Args[n++] = I->File.c_str();
832 Size += strlen(Args[n-1]);
833 }
834 }
835 else
836 {
837 for (;I != J && Size < MaxArgBytes; I++)
838 {
839 if((*I).Pkg.end() == true)
840 continue;
841 Args[n++] = I->Pkg.Name();
842 Size += strlen(Args[n-1]);
843 }
844 }
845 Args[n] = 0;
846 J = I;
847
848 if (_config->FindB("Debug::pkgDPkgPM",false) == true)
849 {
850 for (unsigned int k = 0; k != n; k++)
851 clog << Args[k] << ' ';
852 clog << endl;
853 continue;
854 }
855
856 cout << flush;
857 clog << flush;
858 cerr << flush;
859
860 typedef void (*sighandler_t)(int);
861
862 /* Mask off sig int/quit. We do this because dpkg also does when
863 it forks scripts. What happens is that when you hit ctrl-c it sends
864 it to all processes in the group. Since dpkg ignores the signal
865 it doesn't die but we do! So we must also ignore it */
866 sighandler_t old_SIGQUIT = signal(SIGQUIT,SIG_IGN);
867 sighandler_t old_SIGINT = signal(SIGINT,SIG_IGN);
868
869 // ignore SIGHUP as well (debian #463030)
870 sighandler_t old_SIGHUP = signal(SIGHUP,SIG_IGN);
871
872 struct termios tt;
873 struct winsize win;
874 int master = -1;
875 int slave = -1;
876
877 // if tcgetattr does not return zero there was a error
878 // and we do not do any pty magic
879 if (tcgetattr(0, &tt) == 0)
880 {
881 ioctl(0, TIOCGWINSZ, (char *)&win);
882 if (openpty(&master, &slave, NULL, &tt, &win) < 0)
883 {
884 const char *s = _("Can not write log, openpty() "
885 "failed (/dev/pts not mounted?)\n");
886 fprintf(stderr, "%s",s);
887 if(term_out)
888 fprintf(term_out, "%s",s);
889 master = slave = -1;
890 } else {
891 struct termios rtt;
892 rtt = tt;
893 cfmakeraw(&rtt);
894 rtt.c_lflag &= ~ECHO;
895 // block SIGTTOU during tcsetattr to prevent a hang if
896 // the process is a member of the background process group
897 // http://www.opengroup.org/onlinepubs/000095399/functions/tcsetattr.html
898 sigemptyset(&sigmask);
899 sigaddset(&sigmask, SIGTTOU);
900 sigprocmask(SIG_BLOCK,&sigmask, &original_sigmask);
901 tcsetattr(0, TCSAFLUSH, &rtt);
902 sigprocmask(SIG_SETMASK, &original_sigmask, 0);
903 }
904 }
905
906 // Fork dpkg
907 pid_t Child;
908 _config->Set("APT::Keep-Fds::",fd[1]);
909 // send status information that we are about to fork dpkg
910 if(OutStatusFd > 0) {
911 ostringstream status;
912 status << "pmstatus:dpkg-exec:"
913 << (PackagesDone/float(PackagesTotal)*100.0)
914 << ":" << _("Running dpkg")
915 << endl;
916 write(OutStatusFd, status.str().c_str(), status.str().size());
917 }
918 Child = ExecFork();
919
920 // This is the child
921 if (Child == 0)
922 {
923 if(slave >= 0 && master >= 0)
924 {
925 setsid();
926 ioctl(slave, TIOCSCTTY, 0);
927 close(master);
928 dup2(slave, 0);
929 dup2(slave, 1);
930 dup2(slave, 2);
931 close(slave);
932 }
933 close(fd[0]); // close the read end of the pipe
934
935 if (_config->FindDir("DPkg::Chroot-Directory","/") != "/")
936 {
937 std::cerr << "Chrooting into "
938 << _config->FindDir("DPkg::Chroot-Directory")
939 << std::endl;
940 if (chroot(_config->FindDir("DPkg::Chroot-Directory","/").c_str()) != 0)
941 _exit(100);
942 }
943
944 if (chdir(_config->FindDir("DPkg::Run-Directory","/").c_str()) != 0)
945 _exit(100);
946
947 if (_config->FindB("DPkg::FlushSTDIN",true) == true && isatty(STDIN_FILENO))
948 {
949 int Flags,dummy;
950 if ((Flags = fcntl(STDIN_FILENO,F_GETFL,dummy)) < 0)
951 _exit(100);
952
953 // Discard everything in stdin before forking dpkg
954 if (fcntl(STDIN_FILENO,F_SETFL,Flags | O_NONBLOCK) < 0)
955 _exit(100);
956
957 while (read(STDIN_FILENO,&dummy,1) == 1);
958
959 if (fcntl(STDIN_FILENO,F_SETFL,Flags & (~(long)O_NONBLOCK)) < 0)
960 _exit(100);
961 }
962
963 /* No Job Control Stop Env is a magic dpkg var that prevents it
964 from using sigstop */
965 putenv((char *)"DPKG_NO_TSTP=yes");
966 execvp(Args[0],(char **)Args);
967 cerr << "Could not exec dpkg!" << endl;
968 _exit(100);
969 }
970
971 // apply ionice
972 if (_config->FindB("DPkg::UseIoNice", false) == true)
973 ionice(Child);
974
975 // clear the Keep-Fd again
976 _config->Clear("APT::Keep-Fds",fd[1]);
977
978 // Wait for dpkg
979 int Status = 0;
980
981 // we read from dpkg here
982 int const _dpkgin = fd[0];
983 close(fd[1]); // close the write end of the pipe
984
985 if(slave > 0)
986 close(slave);
987
988 // setups fds
989 sigemptyset(&sigmask);
990 sigprocmask(SIG_BLOCK,&sigmask,&original_sigmask);
991
992 // the result of the waitpid call
993 int res;
994 int select_ret;
995 while ((res=waitpid(Child,&Status, WNOHANG)) != Child) {
996 if(res < 0) {
997 // FIXME: move this to a function or something, looks ugly here
998 // error handling, waitpid returned -1
999 if (errno == EINTR)
1000 continue;
1001 RunScripts("DPkg::Post-Invoke");
1002
1003 // Restore sig int/quit
1004 signal(SIGQUIT,old_SIGQUIT);
1005 signal(SIGINT,old_SIGINT);
1006 signal(SIGHUP,old_SIGHUP);
1007 return _error->Errno("waitpid","Couldn't wait for subprocess");
1008 }
1009
1010 // wait for input or output here
1011 FD_ZERO(&rfds);
1012 if (!stdin_is_dev_null)
1013 FD_SET(0, &rfds);
1014 FD_SET(_dpkgin, &rfds);
1015 if(master >= 0)
1016 FD_SET(master, &rfds);
1017 tv.tv_sec = 1;
1018 tv.tv_nsec = 0;
1019 select_ret = pselect(max(master, _dpkgin)+1, &rfds, NULL, NULL,
1020 &tv, &original_sigmask);
1021 if (select_ret < 0 && (errno == EINVAL || errno == ENOSYS))
1022 select_ret = racy_pselect(max(master, _dpkgin)+1, &rfds, NULL,
1023 NULL, &tv, &original_sigmask);
1024 if (select_ret == 0)
1025 continue;
1026 else if (select_ret < 0 && errno == EINTR)
1027 continue;
1028 else if (select_ret < 0)
1029 {
1030 perror("select() returned error");
1031 continue;
1032 }
1033
1034 if(master >= 0 && FD_ISSET(master, &rfds))
1035 DoTerminalPty(master);
1036 if(master >= 0 && FD_ISSET(0, &rfds))
1037 DoStdin(master);
1038 if(FD_ISSET(_dpkgin, &rfds))
1039 DoDpkgStatusFd(_dpkgin, OutStatusFd);
1040 }
1041 close(_dpkgin);
1042
1043 // Restore sig int/quit
1044 signal(SIGQUIT,old_SIGQUIT);
1045 signal(SIGINT,old_SIGINT);
1046 signal(SIGHUP,old_SIGHUP);
1047
1048 if(master >= 0)
1049 {
1050 tcsetattr(0, TCSAFLUSH, &tt);
1051 close(master);
1052 }
1053
1054 // Check for an error code.
1055 if (WIFEXITED(Status) == 0 || WEXITSTATUS(Status) != 0)
1056 {
1057 // if it was set to "keep-dpkg-runing" then we won't return
1058 // here but keep the loop going and just report it as a error
1059 // for later
1060 bool const stopOnError = _config->FindB("Dpkg::StopOnError",true);
1061
1062 if(stopOnError)
1063 RunScripts("DPkg::Post-Invoke");
1064
1065 if (WIFSIGNALED(Status) != 0 && WTERMSIG(Status) == SIGSEGV)
1066 _error->Error("Sub-process %s received a segmentation fault.",Args[0]);
1067 else if (WIFEXITED(Status) != 0)
1068 _error->Error("Sub-process %s returned an error code (%u)",Args[0],WEXITSTATUS(Status));
1069 else
1070 _error->Error("Sub-process %s exited unexpectedly",Args[0]);
1071
1072 if(stopOnError)
1073 {
1074 CloseLog();
1075 return false;
1076 }
1077 }
1078 }
1079 CloseLog();
1080
1081 if (RunScripts("DPkg::Post-Invoke") == false)
1082 return false;
1083
1084 Cache.writeStateFile(NULL);
1085 return true;
1086 }
1087 /*}}}*/
1088 // pkgDpkgPM::Reset - Dump the contents of the command list /*{{{*/
1089 // ---------------------------------------------------------------------
1090 /* */
1091 void pkgDPkgPM::Reset()
1092 {
1093 List.erase(List.begin(),List.end());
1094 }
1095 /*}}}*/
1096
1097 /* memrchr -- find the last occurrence of a byte in a memory block
1098
1099 Copyright (C) 1991, 1993, 1996, 1997, 1999, 2000, 2003, 2004, 2005,
1100 2006, 2007, 2008 Free Software Foundation, Inc.
1101
1102 Based on strlen implementation by Torbjorn Granlund (tege@sics.se),
1103 with help from Dan Sahlin (dan@sics.se) and
1104 commentary by Jim Blandy (jimb@ai.mit.edu);
1105 adaptation to memchr suggested by Dick Karpinski (dick@cca.ucsf.edu),
1106 and implemented by Roland McGrath (roland@ai.mit.edu).
1107
1108 This program is free software: you can redistribute it and/or modify
1109 it under the terms of the GNU General Public License as published by
1110 the Free Software Foundation; either version 3 of the License, or
1111 (at your option) any later version.
1112
1113 This program is distributed in the hope that it will be useful,
1114 but WITHOUT ANY WARRANTY; without even the implied warranty of
1115 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1116 GNU General Public License for more details.
1117
1118 You should have received a copy of the GNU General Public License
1119 along with this program. If not, see <http://www.gnu.org/licenses/>. */
1120
1121 #if defined _LIBC
1122 # include <memcopy.h>
1123 #else
1124 # include <config.h>
1125 # define reg_char char
1126 #endif
1127
1128 #include <string.h>
1129 #include <limits.h>
1130
1131 #undef __memrchr
1132 #ifdef _LIBC
1133 # undef memrchr
1134 #endif
1135
1136 #ifndef weak_alias
1137 # define __memrchr memrchr
1138 #endif
1139
1140 /* Search no more than N bytes of S for C. */
1141 void *
1142 __memrchr (void const *s, int c_in, size_t n)
1143 {
1144 /* On 32-bit hardware, choosing longword to be a 32-bit unsigned
1145 long instead of a 64-bit uintmax_t tends to give better
1146 performance. On 64-bit hardware, unsigned long is generally 64
1147 bits already. Change this typedef to experiment with
1148 performance. */
1149 typedef unsigned long int longword;
1150
1151 const unsigned char *char_ptr;
1152 const longword *longword_ptr;
1153 longword repeated_one;
1154 longword repeated_c;
1155 unsigned reg_char c;
1156
1157 c = (unsigned char) c_in;
1158
1159 /* Handle the last few bytes by reading one byte at a time.
1160 Do this until CHAR_PTR is aligned on a longword boundary. */
1161 for (char_ptr = (const unsigned char *) s + n;
1162 n > 0 && (size_t) char_ptr % sizeof (longword) != 0;
1163 --n)
1164 if (*--char_ptr == c)
1165 return (void *) char_ptr;
1166
1167 longword_ptr = (const longword *) char_ptr;
1168
1169 /* All these elucidatory comments refer to 4-byte longwords,
1170 but the theory applies equally well to any size longwords. */
1171
1172 /* Compute auxiliary longword values:
1173 repeated_one is a value which has a 1 in every byte.
1174 repeated_c has c in every byte. */
1175 repeated_one = 0x01010101;
1176 repeated_c = c | (c << 8);
1177 repeated_c |= repeated_c << 16;
1178 if (0xffffffffU < (longword) -1)
1179 {
1180 repeated_one |= repeated_one << 31 << 1;
1181 repeated_c |= repeated_c << 31 << 1;
1182 if (8 < sizeof (longword))
1183 {
1184 size_t i;
1185
1186 for (i = 64; i < sizeof (longword) * 8; i *= 2)
1187 {
1188 repeated_one |= repeated_one << i;
1189 repeated_c |= repeated_c << i;
1190 }
1191 }
1192 }
1193
1194 /* Instead of the traditional loop which tests each byte, we will test a
1195 longword at a time. The tricky part is testing if *any of the four*
1196 bytes in the longword in question are equal to c. We first use an xor
1197 with repeated_c. This reduces the task to testing whether *any of the
1198 four* bytes in longword1 is zero.
1199
1200 We compute tmp =
1201 ((longword1 - repeated_one) & ~longword1) & (repeated_one << 7).
1202 That is, we perform the following operations:
1203 1. Subtract repeated_one.
1204 2. & ~longword1.
1205 3. & a mask consisting of 0x80 in every byte.
1206 Consider what happens in each byte:
1207 - If a byte of longword1 is zero, step 1 and 2 transform it into 0xff,
1208 and step 3 transforms it into 0x80. A carry can also be propagated
1209 to more significant bytes.
1210 - If a byte of longword1 is nonzero, let its lowest 1 bit be at
1211 position k (0 <= k <= 7); so the lowest k bits are 0. After step 1,
1212 the byte ends in a single bit of value 0 and k bits of value 1.
1213 After step 2, the result is just k bits of value 1: 2^k - 1. After
1214 step 3, the result is 0. And no carry is produced.
1215 So, if longword1 has only non-zero bytes, tmp is zero.
1216 Whereas if longword1 has a zero byte, call j the position of the least
1217 significant zero byte. Then the result has a zero at positions 0, ...,
1218 j-1 and a 0x80 at position j. We cannot predict the result at the more
1219 significant bytes (positions j+1..3), but it does not matter since we
1220 already have a non-zero bit at position 8*j+7.
1221
1222 So, the test whether any byte in longword1 is zero is equivalent to
1223 testing whether tmp is nonzero. */
1224
1225 while (n >= sizeof (longword))
1226 {
1227 longword longword1 = *--longword_ptr ^ repeated_c;
1228
1229 if ((((longword1 - repeated_one) & ~longword1)
1230 & (repeated_one << 7)) != 0)
1231 {
1232 longword_ptr++;
1233 break;
1234 }
1235 n -= sizeof (longword);
1236 }
1237
1238 char_ptr = (const unsigned char *) longword_ptr;
1239
1240 /* At this point, we know that either n < sizeof (longword), or one of the
1241 sizeof (longword) bytes starting at char_ptr is == c. On little-endian
1242 machines, we could determine the first such byte without any further
1243 memory accesses, just by looking at the tmp result from the last loop
1244 iteration. But this does not work on big-endian machines. Choose code
1245 that works in both cases. */
1246
1247 while (n-- > 0)
1248 {
1249 if (*--char_ptr == c)
1250 return (void *) char_ptr;
1251 }
1252
1253 return NULL;
1254 }
1255 #ifdef weak_alias
1256 weak_alias (__memrchr, memrchr)
1257 #endif